···
1
+
(* See the end of the file for the license *)
2
+
exception Cannot_write
3
+
exception Read_error of string
5
+
let read_error fmt = Printf.ksprintf (fun s -> raise (Read_error s)) fmt
6
+
let magic_string = "\147NUMPY"
7
+
let magic_string_len = String.length magic_string
9
+
type packed_kind = P : (_, _) Bigarray.kind -> packed_kind
11
+
let dtype ~packed_kind =
13
+
match packed_kind with
14
+
| P Bigarray.Char -> "|"
15
+
| P _ -> if Sys.big_endian then ">" else "<"
18
+
match packed_kind with
19
+
| P Bigarray.Int32 -> "i4"
20
+
| P Bigarray.Int64 -> "i8"
21
+
| P Bigarray.Float16 -> "f16"
22
+
| P Bigarray.Float32 -> "f4"
23
+
| P Bigarray.Float64 -> "f8"
24
+
| P Bigarray.Int8_unsigned -> "u1"
25
+
| P Bigarray.Int8_signed -> "i1"
26
+
| P Bigarray.Int16_unsigned -> "u2"
27
+
| P Bigarray.Int16_signed -> "i2"
28
+
| P Bigarray.Char -> "S1"
29
+
| P Bigarray.Complex32 -> "c8" (* 2 32bits float. *)
30
+
| P Bigarray.Complex64 -> "c16" (* 2 64bits float. *)
31
+
| P Bigarray.Int -> failwith "Int is not supported"
32
+
| P Bigarray.Nativeint -> failwith "Nativeint is not supported."
36
+
let map_file file_descr ~pos kind layout shared shape =
37
+
let is_scalar = Array.length shape = 0 in
39
+
Unix.map_file file_descr ~pos kind layout shared
40
+
(if is_scalar then [| 1 |] else shape)
42
+
if is_scalar then Bigarray.reshape array [||] else array
44
+
let fortran_order (type a) ~(layout : a Bigarray.layout) =
46
+
| Bigarray.C_layout -> "False"
47
+
| Bigarray.Fortran_layout -> "True"
51
+
| [| dim1 |] -> Printf.sprintf "%d," dim1
52
+
| dims -> Array.to_list dims |> List.map string_of_int |> String.concat ", "
54
+
let full_header ?header_len ~layout ~packed_kind ~dims () =
56
+
Printf.sprintf "{'descr': '%s', 'fortran_order': %s, 'shape': (%s), }"
57
+
(dtype ~packed_kind) (fortran_order ~layout) (shape ~dims)
60
+
let total_len = String.length header + magic_string_len + 4 + 1 in
61
+
match header_len with
62
+
| None -> if total_len mod 16 = 0 then 0 else 16 - (total_len mod 16)
63
+
| Some header_len ->
64
+
if header_len mod 16 <> 0 then
65
+
failwith "header_len has to be divisible by 16";
66
+
if header_len < total_len then
67
+
failwith "header_len is smaller than total_len";
68
+
header_len - total_len
70
+
let total_header_len = String.length header + padding_len + 1 in
71
+
Printf.sprintf "%s\001\000%c%c%s%s\n" magic_string
72
+
(total_header_len mod 256 |> Char.chr)
73
+
(total_header_len / 256 |> Char.chr)
75
+
(String.make padding_len ' ')
77
+
let with_file filename flags mask ~f =
78
+
let file_descr = Unix.openfile filename flags mask in
80
+
let result = f file_descr in
81
+
Unix.close file_descr;
84
+
Unix.close file_descr;
87
+
let write ?header_len bigarray filename =
88
+
with_file filename [ O_CREAT; O_TRUNC; O_RDWR ] 0o640 ~f:(fun file_descr ->
90
+
full_header () ?header_len
91
+
~layout:(Bigarray.Genarray.layout bigarray)
92
+
~packed_kind:(P (Bigarray.Genarray.kind bigarray))
93
+
~dims:(Bigarray.Genarray.dims bigarray)
95
+
let full_header_len = String.length full_header in
97
+
Unix.write_substring file_descr full_header 0 full_header_len
99
+
then raise Cannot_write;
102
+
~pos:(Int64.of_int full_header_len)
104
+
(Bigarray.Genarray.kind bigarray)
105
+
(Bigarray.Genarray.layout bigarray)
107
+
(Bigarray.Genarray.dims bigarray)
109
+
Bigarray.Genarray.blit bigarray file_array)
111
+
let write1 array1 filename = write (Bigarray.genarray_of_array1 array1) filename
112
+
let write2 array2 filename = write (Bigarray.genarray_of_array2 array2) filename
113
+
let write3 array3 filename = write (Bigarray.genarray_of_array3 array3) filename
115
+
module Batch_writer = struct
116
+
let header_len = 128
119
+
file_descr : Unix.file_descr;
120
+
mutable bytes_written_so_far : int;
121
+
mutable dims_and_packed_kind : (int array * packed_kind) option;
124
+
let append t bigarray =
127
+
~pos:(Int64.of_int t.bytes_written_so_far)
129
+
(Bigarray.Genarray.kind bigarray)
130
+
(Bigarray.Genarray.layout bigarray)
132
+
(Bigarray.Genarray.dims bigarray)
134
+
Bigarray.Genarray.blit bigarray file_array;
135
+
let size_in_bytes = Bigarray.Genarray.size_in_bytes bigarray in
136
+
t.bytes_written_so_far <- t.bytes_written_so_far + size_in_bytes;
137
+
match t.dims_and_packed_kind with
139
+
let dims = Bigarray.Genarray.dims bigarray in
140
+
let kind = Bigarray.Genarray.kind bigarray in
141
+
t.dims_and_packed_kind <- Some (dims, P kind)
142
+
| Some (dims, _kind) ->
143
+
let dims' = Bigarray.Genarray.dims bigarray in
144
+
let incorrect_dimensions =
145
+
match (Array.to_list dims, Array.to_list dims') with
146
+
| [], _ | _, [] -> true
147
+
| _ :: d, _ :: d' -> d <> d'
149
+
if incorrect_dimensions then
150
+
Printf.sprintf "Incorrect dimensions %s vs %s." (shape ~dims)
151
+
(shape ~dims:dims')
153
+
dims.(0) <- dims.(0) + dims'.(0)
155
+
let create filename =
157
+
Unix.openfile filename [ O_CREAT; O_TRUNC; O_RDWR ] 0o640
161
+
bytes_written_so_far = header_len;
162
+
dims_and_packed_kind = None;
166
+
assert (Unix.lseek t.file_descr 0 SEEK_SET = 0);
168
+
match t.dims_and_packed_kind with
169
+
| None -> failwith "Nothing to write"
170
+
| Some (dims, packed_kind) ->
171
+
full_header ~header_len ~layout:C_layout ~dims ~packed_kind ()
173
+
if Unix.write_substring t.file_descr header 0 header_len <> header_len then
174
+
raise Cannot_write;
175
+
Unix.close t.file_descr
178
+
let really_read fd len =
179
+
let buffer = Bytes.create len in
180
+
let rec loop offset =
181
+
let read = Unix.read fd buffer offset (len - offset) in
182
+
if read + offset < len then loop (read + offset)
183
+
else if read = 0 then read_error "unexpected eof"
186
+
Bytes.to_string buffer
188
+
module Header = struct
189
+
type packed_kind = P : (_, _) Bigarray.kind -> packed_kind
190
+
type t = { kind : packed_kind; fortran_order : bool; shape : int array }
192
+
let split str ~on =
193
+
let parens = ref 0 in
194
+
let indexes = ref [] in
195
+
for i = 0 to String.length str - 1 do
197
+
| '(' -> incr parens
198
+
| ')' -> decr parens
199
+
| c when !parens = 0 && c = on -> indexes := i :: !indexes
203
+
(fun (prev_p, acc) index ->
204
+
(index, String.sub str (index + 1) (prev_p - index - 1) :: acc))
205
+
(String.length str, [])
207
+
|> fun (first_pos, acc) -> String.sub str 0 first_pos :: acc
210
+
let rec loopr start len =
211
+
if len = 0 then (start, len)
212
+
else if List.mem str.[start + len - 1] on then loopr start (len - 1)
215
+
let rec loopl start len =
216
+
if len = 0 then (start, len)
217
+
else if List.mem str.[start] on then loopl (start + 1) (len - 1)
218
+
else loopr start len
220
+
let start, len = loopl 0 (String.length str) in
221
+
String.sub str start len
224
+
let header_fields =
225
+
trim header ~on:[ '{'; ' '; '}'; '\n' ]
227
+
|> List.map String.trim
228
+
|> List.filter (fun s -> String.length s > 0)
229
+
|> List.map (fun header_field ->
230
+
match split header_field ~on:':' with
231
+
| [ name; value ] ->
232
+
( trim name ~on:[ '\''; ' ' ],
233
+
trim value ~on:[ '\''; ' '; '('; ')' ] )
234
+
| _ -> read_error "unable to parse field %s" header_field)
236
+
let find_field field =
237
+
try List.assoc field header_fields
238
+
with Not_found -> read_error "cannot find field %s" field
241
+
let kind = find_field "descr" in
242
+
(match kind.[0] with
245
+
if not Sys.big_endian then
246
+
read_error "big endian data but arch is little endian"
248
+
if Sys.big_endian then
249
+
read_error "little endian data but arch is big endian"
250
+
| otherwise -> read_error "incorrect endianness %c" otherwise);
251
+
match String.sub kind 1 (String.length kind - 1) with
252
+
| "f2" -> P Float16
253
+
| "f4" -> P Float32
254
+
| "f8" -> P Float64
257
+
| "u1" -> P Int8_unsigned
258
+
| "i1" -> P Int8_signed
259
+
| "u2" -> P Int16_unsigned
260
+
| "i2" -> P Int16_signed
262
+
| "c8" -> P Complex32
263
+
| "c16" -> P Complex64
264
+
| otherwise -> read_error "incorrect descr %s" otherwise
266
+
let fortran_order =
267
+
match find_field "fortran_order" with
270
+
| otherwise -> read_error "incorrect fortran_order %s" otherwise
275
+
|> List.map String.trim
276
+
|> List.filter (fun s -> String.length s > 0)
277
+
|> List.map int_of_string
280
+
{ kind; fortran_order; shape }
283
+
type packed_array = P : (_, _, _) Bigarray.Genarray.t -> packed_array
284
+
type packed_array1 = P1 : (_, _, _) Bigarray.Array1.t -> packed_array1
285
+
type packed_array2 = P2 : (_, _, _) Bigarray.Array2.t -> packed_array2
286
+
type packed_array3 = P3 : (_, _, _) Bigarray.Array3.t -> packed_array3
288
+
let read_mmap filename ~shared =
289
+
let access = if shared then Unix.O_RDWR else O_RDONLY in
290
+
let file_descr = Unix.openfile filename [ access ] 0 in
293
+
let magic_string' = really_read file_descr magic_string_len in
294
+
if magic_string <> magic_string' then read_error "magic string mismatch";
295
+
let version = really_read file_descr 2 |> fun v -> v.[0] |> Char.code in
296
+
let header_len_len =
300
+
| _ -> read_error "unsupported version %d" version
302
+
let header, header_len =
303
+
really_read file_descr header_len_len |> fun str ->
304
+
let header_len = ref 0 in
305
+
for i = String.length str - 1 downto 0 do
306
+
header_len := (256 * !header_len) + Char.code str.[i]
308
+
(really_read file_descr !header_len, !header_len)
310
+
let header = Header.parse header in
311
+
(Int64.of_int (header_len + header_len_len + magic_string_len + 2), header)
313
+
Unix.close file_descr;
316
+
let (Header.P kind) = header.kind in
318
+
let array = map_file file_descr ~pos kind layout shared header.shape in
319
+
Gc.finalise (fun _ -> Unix.close file_descr) array;
322
+
if header.fortran_order then build Fortran_layout else build C_layout
324
+
let read_mmap1 filename ~shared =
325
+
let (P array) = read_mmap filename ~shared in
326
+
P1 (Bigarray.array1_of_genarray array)
328
+
let read_mmap2 filename ~shared =
329
+
let (P array) = read_mmap filename ~shared in
330
+
P2 (Bigarray.array2_of_genarray array)
332
+
let read_mmap3 filename ~shared =
333
+
let (P array) = read_mmap filename ~shared in
334
+
P3 (Bigarray.array3_of_genarray array)
336
+
let read_copy filename =
337
+
let (P array) = read_mmap filename ~shared:false in
339
+
Bigarray.Genarray.create
340
+
(Bigarray.Genarray.kind array)
341
+
(Bigarray.Genarray.layout array)
342
+
(Bigarray.Genarray.dims array)
344
+
Bigarray.Genarray.blit array result;
347
+
let read_copy1 filename =
348
+
let (P array) = read_copy filename in
349
+
P1 (Bigarray.array1_of_genarray array)
351
+
let read_copy2 filename =
352
+
let (P array) = read_copy filename in
353
+
P2 (Bigarray.array2_of_genarray array)
355
+
let read_copy3 filename =
356
+
let (P array) = read_copy filename in
357
+
P3 (Bigarray.array3_of_genarray array)
359
+
module Npz = struct
360
+
let npy_suffix = ".npy"
362
+
let maybe_add_suffix array_name ~suffix =
364
+
match suffix with None -> npy_suffix | Some suffix -> suffix
366
+
array_name ^ suffix
368
+
type in_file = Zip.in_file
370
+
let open_in = Zip.open_in
374
+
|> List.map (fun entry ->
375
+
let filename = entry.Zip.filename in
376
+
if String.length filename < String.length npy_suffix then filename
378
+
let start_pos = String.length filename - String.length npy_suffix in
380
+
String.sub filename start_pos (String.length npy_suffix)
382
+
then String.sub filename 0 start_pos
385
+
let close_in = Zip.close_in
387
+
let read ?suffix t array_name =
388
+
let array_name = maybe_add_suffix array_name ~suffix in
390
+
try Zip.find_entry t array_name
392
+
raise (Invalid_argument ("unable to find " ^ array_name))
394
+
let tmp_file = Filename.temp_file "ocaml-npz" ".tmp" in
395
+
Zip.copy_entry_to_file t entry tmp_file;
396
+
let data = read_copy tmp_file in
397
+
Sys.remove tmp_file;
400
+
type out_file = Zip.out_file
402
+
let open_out filename = Zip.open_out filename
403
+
let close_out = Zip.close_out
405
+
let write ?suffix t array_name array =
406
+
let array_name = maybe_add_suffix array_name ~suffix in
407
+
let tmp_file = Filename.temp_file "ocaml-npz" ".tmp" in
408
+
write array tmp_file;
409
+
Zip.copy_file_to_entry tmp_file t array_name;
410
+
Sys.remove tmp_file
413
+
(** Type equalities module, used in conversion function *)
415
+
(** An equality type to extract type equalities *)
416
+
type ('a, 'b) t = W : ('a, 'a) t
420
+
(** Type equalities for bigarray kinds *)
421
+
module Kind = struct
422
+
let ( === ) : type a b c d.
423
+
(a, b) kind -> (c, d) kind -> ((a, b) kind, (c, d) kind) t option =
426
+
| Float32, Float32 -> Some W
427
+
| Float64, Float64 -> Some W
428
+
| Int8_signed, Int8_signed -> Some W
429
+
| Int8_unsigned, Int8_unsigned -> Some W
430
+
| Int16_signed, Int16_signed -> Some W
431
+
| Int16_unsigned, Int16_unsigned -> Some W
432
+
| Int32, Int32 -> Some W
433
+
| Int64, Int64 -> Some W
434
+
| Int, Int -> Some W
435
+
| Nativeint, Nativeint -> Some W
436
+
| Complex32, Complex32 -> Some W
437
+
| Complex64, Complex64 -> Some W
438
+
| Char, Char -> Some W
442
+
(** Type equalities for layout *)
443
+
module Layout = struct
444
+
let ( === ) : type a b.
445
+
a layout -> b layout -> (a layout, b layout) t option =
448
+
| Fortran_layout, Fortran_layout -> Some W
449
+
| C_layout, C_layout -> Some W
454
+
(** Conversion functions from packed arrays to bigarrays *)
456
+
let to_bigarray (type a b c) (layout : c Bigarray.layout)
457
+
(kind : (a, b) Bigarray.kind) (P x) =
458
+
match Eq.Layout.(Bigarray.Genarray.layout x === layout) with
461
+
match Eq.Kind.(Bigarray.Genarray.kind x === kind) with
463
+
| Some Eq.W -> Some (x : (a, b, c) Bigarray.Genarray.t))
465
+
let to_bigarray1 (type a b c) (layout : c Bigarray.layout)
466
+
(kind : (a, b) Bigarray.kind) (P1 x) =
467
+
match Eq.Layout.(Bigarray.Array1.layout x === layout) with
470
+
match Eq.Kind.(Bigarray.Array1.kind x === kind) with
472
+
| Some Eq.W -> Some (x : (a, b, c) Bigarray.Array1.t))
474
+
let to_bigarray2 (type a b c) (layout : c Bigarray.layout)
475
+
(kind : (a, b) Bigarray.kind) (P2 x) =
476
+
match Eq.Layout.(Bigarray.Array2.layout x === layout) with
479
+
match Eq.Kind.(Bigarray.Array2.kind x === kind) with
481
+
| Some Eq.W -> Some (x : (a, b, c) Bigarray.Array2.t))
483
+
let to_bigarray3 (type a b c) (layout : c Bigarray.layout)
484
+
(kind : (a, b) Bigarray.kind) (P3 x) =
485
+
match Eq.Layout.(Bigarray.Array3.layout x === layout) with
488
+
match Eq.Kind.(Bigarray.Array3.kind x === kind) with
490
+
| Some Eq.W -> Some (x : (a, b, c) Bigarray.Array3.t))
494
+
Version 2.0, January 2004
495
+
http://www.apache.org/licenses/
497
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
501
+
"License" shall mean the terms and conditions for use, reproduction,
502
+
and distribution as defined by Sections 1 through 9 of this document.
504
+
"Licensor" shall mean the copyright owner or entity authorized by
505
+
the copyright owner that is granting the License.
507
+
"Legal Entity" shall mean the union of the acting entity and all
508
+
other entities that control, are controlled by, or are under common
509
+
control with that entity. For the purposes of this definition,
510
+
"control" means (i) the power, direct or indirect, to cause the
511
+
direction or management of such entity, whether by contract or
512
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
513
+
outstanding shares, or (iii) beneficial ownership of such entity.
515
+
"You" (or "Your") shall mean an individual or Legal Entity
516
+
exercising permissions granted by this License.
518
+
"Source" form shall mean the preferred form for making modifications,
519
+
including but not limited to software source code, documentation
520
+
source, and configuration files.
522
+
"Object" form shall mean any form resulting from mechanical
523
+
transformation or translation of a Source form, including but
524
+
not limited to compiled object code, generated documentation,
525
+
and conversions to other media types.
527
+
"Work" shall mean the work of authorship, whether in Source or
528
+
Object form, made available under the License, as indicated by a
529
+
copyright notice that is included in or attached to the work
530
+
(an example is provided in the Appendix below).
532
+
"Derivative Works" shall mean any work, whether in Source or Object
533
+
form, that is based on (or derived from) the Work and for which the
534
+
editorial revisions, annotations, elaborations, or other modifications
535
+
represent, as a whole, an original work of authorship. For the purposes
536
+
of this License, Derivative Works shall not include works that remain
537
+
separable from, or merely link (or bind by name) to the interfaces of,
538
+
the Work and Derivative Works thereof.
540
+
"Contribution" shall mean any work of authorship, including
541
+
the original version of the Work and any modifications or additions
542
+
to that Work or Derivative Works thereof, that is intentionally
543
+
submitted to Licensor for inclusion in the Work by the copyright owner
544
+
or by an individual or Legal Entity authorized to submit on behalf of
545
+
the copyright owner. For the purposes of this definition, "submitted"
546
+
means any form of electronic, verbal, or written communication sent
547
+
to the Licensor or its representatives, including but not limited to
548
+
communication on electronic mailing lists, source code control systems,
549
+
and issue tracking systems that are managed by, or on behalf of, the
550
+
Licensor for the purpose of discussing and improving the Work, but
551
+
excluding communication that is conspicuously marked or otherwise
552
+
designated in writing by the copyright owner as "Not a Contribution."
554
+
"Contributor" shall mean Licensor and any individual or Legal Entity
555
+
on behalf of whom a Contribution has been received by Licensor and
556
+
subsequently incorporated within the Work.
558
+
2. Grant of Copyright License. Subject to the terms and conditions of
559
+
this License, each Contributor hereby grants to You a perpetual,
560
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
561
+
copyright license to reproduce, prepare Derivative Works of,
562
+
publicly display, publicly perform, sublicense, and distribute the
563
+
Work and such Derivative Works in Source or Object form.
565
+
3. Grant of Patent License. Subject to the terms and conditions of
566
+
this License, each Contributor hereby grants to You a perpetual,
567
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
568
+
(except as stated in this section) patent license to make, have made,
569
+
use, offer to sell, sell, import, and otherwise transfer the Work,
570
+
where such license applies only to those patent claims licensable
571
+
by such Contributor that are necessarily infringed by their
572
+
Contribution(s) alone or by combination of their Contribution(s)
573
+
with the Work to which such Contribution(s) was submitted. If You
574
+
institute patent litigation against any entity (including a
575
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
576
+
or a Contribution incorporated within the Work constitutes direct
577
+
or contributory patent infringement, then any patent licenses
578
+
granted to You under this License for that Work shall terminate
579
+
as of the date such litigation is filed.
581
+
4. Redistribution. You may reproduce and distribute copies of the
582
+
Work or Derivative Works thereof in any medium, with or without
583
+
modifications, and in Source or Object form, provided that You
584
+
meet the following conditions:
586
+
(a) You must give any other recipients of the Work or
587
+
Derivative Works a copy of this License; and
589
+
(b) You must cause any modified files to carry prominent notices
590
+
stating that You changed the files; and
592
+
(c) You must retain, in the Source form of any Derivative Works
593
+
that You distribute, all copyright, patent, trademark, and
594
+
attribution notices from the Source form of the Work,
595
+
excluding those notices that do not pertain to any part of
596
+
the Derivative Works; and
598
+
(d) If the Work includes a "NOTICE" text file as part of its
599
+
distribution, then any Derivative Works that You distribute must
600
+
include a readable copy of the attribution notices contained
601
+
within such NOTICE file, excluding those notices that do not
602
+
pertain to any part of the Derivative Works, in at least one
603
+
of the following places: within a NOTICE text file distributed
604
+
as part of the Derivative Works; within the Source form or
605
+
documentation, if provided along with the Derivative Works; or,
606
+
within a display generated by the Derivative Works, if and
607
+
wherever such third-party notices normally appear. The contents
608
+
of the NOTICE file are for informational purposes only and
609
+
do not modify the License. You may add Your own attribution
610
+
notices within Derivative Works that You distribute, alongside
611
+
or as an addendum to the NOTICE text from the Work, provided
612
+
that such additional attribution notices cannot be construed
613
+
as modifying the License.
615
+
You may add Your own copyright statement to Your modifications and
616
+
may provide additional or different license terms and conditions
617
+
for use, reproduction, or distribution of Your modifications, or
618
+
for any such Derivative Works as a whole, provided Your use,
619
+
reproduction, and distribution of the Work otherwise complies with
620
+
the conditions stated in this License.
622
+
5. Submission of Contributions. Unless You explicitly state otherwise,
623
+
any Contribution intentionally submitted for inclusion in the Work
624
+
by You to the Licensor shall be under the terms and conditions of
625
+
this License, without any additional terms or conditions.
626
+
Notwithstanding the above, nothing herein shall supersede or modify
627
+
the terms of any separate license agreement you may have executed
628
+
with Licensor regarding such Contributions.
630
+
6. Trademarks. This License does not grant permission to use the trade
631
+
names, trademarks, service marks, or product names of the Licensor,
632
+
except as required for reasonable and customary use in describing the
633
+
origin of the Work and reproducing the content of the NOTICE file.
635
+
7. Disclaimer of Warranty. Unless required by applicable law or
636
+
agreed to in writing, Licensor provides the Work (and each
637
+
Contributor provides its Contributions) on an "AS IS" BASIS,
638
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
639
+
implied, including, without limitation, any warranties or conditions
640
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
641
+
PARTICULAR PURPOSE. You are solely responsible for determining the
642
+
appropriateness of using or redistributing the Work and assume any
643
+
risks associated with Your exercise of permissions under this License.
645
+
8. Limitation of Liability. In no event and under no legal theory,
646
+
whether in tort (including negligence), contract, or otherwise,
647
+
unless required by applicable law (such as deliberate and grossly
648
+
negligent acts) or agreed to in writing, shall any Contributor be
649
+
liable to You for damages, including any direct, indirect, special,
650
+
incidental, or consequential damages of any character arising as a
651
+
result of this License or out of the use or inability to use the
652
+
Work (including but not limited to damages for loss of goodwill,
653
+
work stoppage, computer failure or malfunction, or any and all
654
+
other commercial damages or losses), even if such Contributor
655
+
has been advised of the possibility of such damages.
657
+
9. Accepting Warranty or Additional Liability. While redistributing
658
+
the Work or Derivative Works thereof, You may choose to offer,
659
+
and charge a fee for, acceptance of support, warranty, indemnity,
660
+
or other liability obligations and/or rights consistent with this
661
+
License. However, in accepting such obligations, You may act only
662
+
on Your own behalf and on Your sole responsibility, not on behalf
663
+
of any other Contributor, and only if You agree to indemnify,
664
+
defend, and hold each Contributor harmless for any liability
665
+
incurred by, or claims asserted against, such Contributor by reason
666
+
of your accepting any such warranty or additional liability.
668
+
END OF TERMS AND CONDITIONS
670
+
APPENDIX: How to apply the Apache License to your work.
672
+
To apply the Apache License to your work, attach the following
673
+
boilerplate notice, with the fields enclosed by brackets "{}"
674
+
replaced with your own identifying information. (Don't include
675
+
the brackets!) The text should be enclosed in the appropriate
676
+
comment syntax for the file format. We also recommend that a
677
+
file or class name and description of purpose be included on the
678
+
same "printed page" as the copyright notice for easier
679
+
identification within third-party archives.
681
+
Copyright {yyyy} {name of copyright owner}
683
+
Licensed under the Apache License, Version 2.0 (the "License");
684
+
you may not use this file except in compliance with the License.
685
+
You may obtain a copy of the License at
687
+
http://www.apache.org/licenses/LICENSE-2.0
689
+
Unless required by applicable law or agreed to in writing, software
690
+
distributed under the License is distributed on an "AS IS" BASIS,
691
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
692
+
See the License for the specific language governing permissions and
693
+
limitations under the License. *)