pax_global_header00006660000000000000000000000064125646107550014525gustar00rootroot0000000000000052 comment=7aab69d44ca6cf8cd1c766b4435ad39f4ae14e83 core-113.00.00/000077500000000000000000000000001256461075500127575ustar00rootroot00000000000000core-113.00.00/.gitignore000066400000000000000000000001521256461075500147450ustar00rootroot00000000000000_build/ /setup.data /setup.log /*.exe /*.docdir /*.native /*.byte /lib/core_config.h /lib/core_config.mlh core-113.00.00/CHANGES.md000066400000000000000000002014641256461075500143600ustar00rootroot00000000000000## 113.00.00 - Added support to `Time` and `Time.Ofday` for parsing leap second times to the last representable moment in the day. - Removed hack in `Time` for fast division by ten, since it's now part of the OCaml compiler. let div_by_10 i = i / 10 let div_by_10_hack i = (i * 1717986919) lsr 34 BENCH "div_by_10" = for i = 0 to 10000 do ignore (div_by_10 i) done BENCH "div_by_10_hack" = for i = 0 to 10000 do ignore (div_by_10_hack i) done +--------------------------------------------+----------+------------+ | Name | Time/Run | Percentage | +--------------------------------------------+----------+------------+ | [time_internal.ml:Helpers] div_by_10 | 5.56us | 99.93% | | [time_internal.ml:Helpers] div_by_10_hack | 5.57us | 100.00% | +--------------------------------------------+----------+------------+ - Added `Unix.Cidr.all_matching_addresses`. val all_matching_addresses : t -> Inet_addr.t Sequence.t. - Renamed `Iobuf` `padded_fixed_string` functions as `tail_padded_fixed_string`. This was done because `padded_fixed_string` does not allow padding on both sides; padding is only permitted at the tail end of the string. - Added `Limiter` module Implements a token bucket based throttling rate limiter. This module is useful for limiting network clients to a sensible query rate, or in any case where you have jobs that consume a scarce, but replenishable resource. - Added to `Time_stamp_counter` some `BENCH` benchmarks. - Added `Iobuf.Expert` module, for building low-cost syscall wrappers outside of the `Iobuf` module. - Implemented `Time_ns.Ofday.of_string`, which previously raised. - Fixed a bug in `Command.shape`, which did not preserve environment variables that executables run by `Command.exec` might need in order to function. - Removed `Time.Ofday.end_of_day`. `Time.Ofday` historically offered a value `end_of_day`. This value was defined as 24 hours after `start_of_day` which created the odd situation where `end_of_day` equals `start_of_day` on the following day. This value has been removed because using `end_of_day` leads to odd results, especially in cases where it is used assuming that events at this time will happen on a particular date. - Added `Command.Spec.of_params`, to help ease the transition from `Spec` to `Param`. val of_params : ('a, 'b) Param.Args.t -> ('a, 'b) Spec.t - Made `Time.Zone.t_of_sexp` accept `Local` for the local timezone. - Moved `Time_ns.pause` functions from `Core_kernel` to `Core`. ## 112.35.00 - Tweaked `Unix.stat`'s C code to reduce float rounding error, by using double-precision rather than single-precision floats. Following Xavier's comment: http://caml.inria.fr/mantis/view.php?id=6285 - Added `Date.O` module. - In `Interval`, exposed `compare` in stable types by having the appropriate modules match the `Stable` signature. - Added `Iobuf.Fill.decimal` and `Poke.decimal`, for efficiently writing integers in decimal format. - Removed `Filename.O` (and `/^`), since it's not used that much, and is inconsistent with the older operator for this that's exposed in `Core.Std`: `^/`. - Improved `Command` autocompletion to work even if some arguments can't be parsed. This is useful because the completion mode does not get fed precisely the same arguments that it would get if you hit RETURN. As a simple example, if completion is set up for `my-exe` which takes a sexp as its first argument, then: my-exe '(a b)' will run `my-exe` in completion mode with: '(a b)' as its first argument, rather than: (a b) as would be passed if RETURN had been pressed instead. Since `Sexp.of_string "'(a b)'"` fails, in this example tab completion won't work. Changed the internals a bit to make this possible. Most notably, the `Parser` module is now applicative rather than monadic, which required only a few simple changes to support. - Made `Time_ns.to_time` and `Time_ns.Span.to_span` round to the nearest microsecond in all cases. Previously, `Time_ns.Span.to_span` sometimes rounded incorrectly for negative spans. - Added `Time.Zone.prev_clock_shift`, the analog of `next_clock_shift`. val prev_clock_shift : t -> before:Time_internal.T.t -> (Time_internal.T.t * Span.t) option Implemented `next_clock_shift` and `prev_clock_shift` using `Array.binary_search_segmented`. - Added `Lock_file.get_pid : string -> Pid.t option`. - Added `val random: unit -> int` to `Time_ns` and `Time_ns.Span`. - Renamed `Iobuf.sub` as `Iobuf.sub_shared`. This more closely matches `Bigstring`, and clarifies the semantics of `Iobuf.sub` vs `sub` in `Blit_intf.S`. - Added `Iobuf` blit modules: `Blit`, `Blit_consume`, `Blit_fill`, `Blit_consume_and_fill`. - Added `Piecewise_linear.first_knot` and `last_knot`. val first_knot : t -> (key * value) option val last_knot : t -> (key * value) option - Made `Unix.Cidr` match `Comparable.S_binable`, and added `Cidr.create` and `Cidr.netmask_of_bits`. - Moved `Unix.tm` and `Unix.strftime` from `Core_kernel` to `Core`. - Made `Crc.crc32` return `Int63.t` rather than `int64`, and added `Crc.bigstring_crc32` and `Iobuf.crc32`. Cleaned up old cruft in the C stubs for CRC checking. - Added `Iobuf.narrow_lo` and `narrow_hi`, which comprise `Iobuf.narrow`. - Changed `Linux_ext.Timerfd`, `Epoll.wait`, and `Unix.select` to use (`int`) `Time_ns` rather than (`float`) `Time`. This avoids spurious float conversions and rounding problems. Made all timeouts consistently treat negative timeouts as "timeout immediately". This fixes an incorrect behavior of `Linux_ext.Timerfd.set_after` and `set`, which had been rounding to the nearest microsecond, which was particularly bad for time spans smaller than 500ns, which would be rounded to zero, and then would cause the timerfd to never fire. Now, the small span is directly fed to `timerfd_settime`. We also changed a span of zero to be treated as `1ns`, to avoid the behavior of `timerfd_settime 0`, which causes the timerfd to be cleared and never fire. - Made `Or_error` match `Applicative.S`. - Added `Command.Param`, with the intention of one day replacing `Command.Spec` and providing an applicative interface for command-line parsing. This change required lots of rearrangement of `command.mli` so that `Command.Param` and `Command.Spec` could share large portions of their interface. As a side effect, the interface is more sweeksy than before. - Added `Command.shape`, for exposing the shape of a command, including what subcommands its has. - Changed `Syscall_result.to_result` to return a preallocated object, and changed many uses to take advantage of this property. Pattern matching on results is much clearer than if-analysis and avoids double-checking errors in many cases. `Syscall_result.to_result` can only return preallocated results for a few `Ok` values from `Syscall_result.Int`, of course, and likewise for other large `ok_value` types. We have initially, and arbitrarily, limited preallocation to 64 `errno`'s and 2048 `ok_value`'s. - Added `Sys.big_endian : bool`, from `Caml.Sys`. - Disabled unit tests in `Time_ns` that started failing around 10:40pm NYC 2015-05-15. The tests indicate an off-by-one-microsecond error in round tripping between `Time.Span.t` and `Time_ns.Span.t`. ## 112.24.00 - Renamed `Dequeue` as `Deque`. - Added `Fdeque`, a functional deque (a double-ended `Fqueue`, or a functional `Deque`). - Changed `Fqueue`'s bin-io format, and added a stable type. Deprecated deque-like functions in favor of `Fdeque`. - Added `Fheap`, a functional heap implementation based on pairing heaps. - Reverted the change to `Or_error`'s bin-io format made in 112.17, going back to the format in 112.16 and before. - Added to `Unix.env` type a ``Replace_raw` variant, as used in `exec` and `fork_exec`. - Added `Array.Permissioned` module, which has a permissioned array type and permissioned versions of all the regular array functions. - Added `Date.week_number : t -> int`. - Added values to `Day_of_week`: `of_int_exn`, `iso_8601_weekday_number`, `weekdays`. val of_int_exn : int -> t val iso_8601_weekday_number : t -> int val weekdays : t list (- [ Mon; Tue; Wed; Thu; Fri ] *) - Switched `Float` IEEE functions to use `Int63.t` for the mantissa rather than `int`, so they work on 32-bit platforms. - Added a `length` field to the `Map.t` record, making `Map.length` `O(1)` rather than `O(n)`. - Moved a fragment of `Time_ns` from `Core` to `Core_kernel`, enough so that `Async_kernel` can use `Core_kernel.Time_ns` and ultimately only depend on `Core_kernel`. - Fixed compilation of `Time_ns` 32-bit Linux. - Added `Bounded_int_table.clear`. - Fixed the `module_name` passed to `Identifiable.Make` for a number of modules. The module name must be an absolute module path. Reported here: https://github.com/janestreet/core/issues/52 - Added `Tuple.Binable` functor, for making binable tuples. - Sped up a `Time_stamp_counter` unit test. `Time_stamp_counter` unit test has an 18s unit test, which seems excessive. Take a couple of orders of magnitude off the number of iterations. - Added `Time_ns.pause`, whose implementation is the same as `Time.pause`. This involved moving the `nanosleep` C code from `Core` to `Core_kernel`. This was necessary so that `Async_kernel` can pause without introducing a dependence of Async on Core. - Made `Core_kernel.Time_ns.Alternate_sexp` use a similar format to `Core.Time_ns`. This was needed so that `Async_kernel` can use a nice sexp format for time spans. - Changed `Timing_wheel` implementation to use `Time_ns`, and moved to `Core_kernel.Timing_wheel_ns`; made `Core.Timing_wheel` a wrapper around `Timing_wheel_ns`. Generalized the timing-wheel interface to be parametric in `Time`, so that one interface applies to both `Timing_wheel` and `Timing_wheel_ns`. Generalized the timing-wheel unit tests to a functor, `Timing_wheel_unit_tests.Make`, that is used to test both `Timing_wheel_ns` and `Timing_wheel_float`. Moved a few tests that depend on `Time` and `Date` from the functor into `timing_wheel_float_unit_tests.ml`. Split out `Timing_wheel.Debug` into a separate functor, `Timing_wheel_debug.Make`. This was done in so that `Async_kernel` can depend only on `Core_kernel` and not `Core`. - Added optional arguments to `Command.group`: `?body` and `?preserve_subcommand_order`. `preserve_subcommand_order : unit` causes subcommands to be in the order they are specified, rather than sorted. `body : (path:string list -> unit)` is called when no additional arguments are passed. - Added accessor function `Command.summary : t -> string`. - Fixed a bug in `Time.Span` robust comparison. - Changed `Command`'s tab-completion bash code so that it is possible for programs to return completions containing spaces. Actually knowing when and how to do so is difficult, because of course there's escaping to worry about. Adding helper functions to make that sort of thing manageable is left for future work. - In `Command`, made the `-version` and `-build-info` flags work at the top level when there are subcommands. - Added `Sequence.interleaved_cartesian_product`, which implements cartesian product of potentially infinite sequences. ## 112.17.00 - Deprecated the single-line files that simply `include` the corresponding Core_kernel module. Those are unnecessary, because people should use `Core.Std`. We will keep these aliases around for a version before deleted them entirely. - Changed finalizers and signal handlers to, upon an unhandled exception, exit nonzero rather than asynchronously raise. - Removed `Time.Zone.find_office`. Replaced uses with the still-blocking `Time.Zone.find_exn` - Made many changes to `Time` to make the time zone explicit instead of implicitly using the local timezone. Added `zone:Time.Zone.t` parameters to many functions. In almost all cases, used `~zone:Time.Zone.local` where previously it was implicit. Removed `of_local_ofday` and `to_local_ofday` in favor of the explicit versions (with `Time.Zone.local`). Removed `Time.Zone.machine_zone ()` in favor of `local`. - Exported `Core.Std.With_return`. - Exposed `Core.Std.with_return_option`. - Fixed `Time_ns.Ofday.of_span_since_start_of_day` to check its input. - Changed `Time_ns.to_span` and `of_span` to round to microseconds, for round trippability. - Added `Unix.Error` module, for the `Unix.error` type. - Added `Unix.Syscall_result`, a new abstract type representing the result of a Unix system call as an `int`, to avoid allocation. A lot of Unix system calls return an integer on success, so for ones that are called a lot, we can encode errors as `-errno`. This module abstracts this concept. - Changed `Iobuf.recvmmsg` functions to return the new `Unix.Syscall_result`. - Changed `Unix.exec`'s `?env` argument to support extending the environment in addition to replacing it. - Added `with compare` to `Unix.Exit.t` and `Unix.Exit_or_signal.t`. - Moved `Backtrace` to `Core_kernel`. Deleted `backtrace_stubs.c`, now that we have `Printexc.get_callstack`. - Changed `Bigstring.read_assume_fd_is_nonblocking` and `send_nonblocking_no_sigpipe` to return `Unix.Syscall_result.t`, to reduce allocation. - Changed `Iobuf.send_nonblocking_no_sigpipe` to handle `EINTR` like `EAGAIN`, instead of raising. - Added `Command.Spec.char`. - Changed `Process_env.parse_ssh_client` to accept an `SSH_CLIENT` that is just IP address without ports. ## 112.06.00 - Renamed `Linux_ext.gettid` as `Unix.gettid`, and added OpenBSD support. `SYS_gettid` is not available on OpenBSD, but is used in `Core_extended`. See the mailing list discussion about this here: https://groups.google.com/forum/#!topic/ocaml-core/51knlnuJ8MM Seems like the OpenBSD alternative is: pid_t getthrid(void); although it's not defined in any header file, which is a bit unfortunate. - Added `Piecewise_linear.precache`, which computes a lookup table that speeds up subsequent calls to `Piecewise_linear.get`. - Added `Time_ns` module, representing times as 63-bit integers of nanoseconds since the epoch. - Fixed build of `unix_stubs.c` on OpenBSD. - In `Daemon`, fixed an error message regarding `WSTOPPED` (fixes #47). - Added `Time.Span.Stable.V2`, with sexps that use new suffixes for microseconds (`us`) and nanoseconds (`ns`). `Time.Span.of_string` supports the new format, but `Time.Span.to_string` doesn't yet produce it -- we plan to change that later, after the new `of_string` has made it out more widely. - Added `Time.Span.to_string_hum`, which gives more options for rendering time spans. - Merged the `recvmmsg` stubs in `Bigstring` and `Iobuf`. Factored out a shared underlying `recvmmsg` call that both stubs use. Restored `-pedantic` by avoiding a C99 feature (variable-length stack arrays). - Made `Date.t` abstract, and changed its representation from a 4-word record to an immediate int (packing year, month, day). - In `Daemon`, changed the permissions of the `std{err,out}` files generated during daemonization from `0o777` to `0o644`. - Moved `Thread_safe_queue` from `core` to `core_kernel`. This was done so that `Async_kernel` can use it, eliminating one of `Async_kernel`'s dependencies on `Core`. `Thread_safe_queue_unit_tests` remains `Core`, at least for now, because it has some dependencies on other stuff in `Core`. ## 112.01.00 - Removed vestigial code supporting OCaml 4.00. - Added `Command` support for flags that are passed one or more times. Added `Command.Spec.one_or_more` and `Command.Spec.non_empty_sequence` to deal with the cases where you expect a flag or anonymous argument (respectively) to be passed one or (optionally) more times. This is common enough and distinct from the case where you want the argument passed zero or more times that it seems like we should canonize it in the library. - In `Lock_file`, made stale lock detection more robust. Made `Lock_file.create foo` succeed if `foo` is absent and `foo.nfs_lock` file is present and stale. Previously, it would fail. - Removed `Syslog.syslog`'s `add_stderr` argument; use the `PERROR` option instead. - Fixed `unix_stubs.c` compilation on NetBSD Closes #45 - Added `Filename` operators `/^` and `/@`, and `of_parts`, like the same functions for Catalog paths. - Changed `Iobuf` functions that advance the iobuf to not also return a redundant number of bytes processed. This avoids a small allocation (in the case of the `int option` functions) and normalizes the result (so the same information isn't returned two ways). Actually, it doesn't yet avoid the allocation in the implementation, as the corresponding `Bigstring` functions must still return the number of bytes processed, and currently do so as an option. We hope to eventually change that. In the future I expect we will change `unit` to some `error` variant to also avoid the exception construction for `EWOULDBLOCK/EAGAIN`. We can even make Unix syscalls `noalloc` if we're careful. - In `Unix` module, added unit tests for `Cidr.does_match`. ## 111.28.00 - Added `Piecewise_linear.create_from_linear_combination`. val create_from_linear_combination : (t * float) list -> t Or_error.t - Added `Time.is_{earlier,later} : Time.t -> than:Time.t -> bool`, which are easier to read than `Time.(<)` and friends. - Added `Command.exec`, which allows one to include the `Command` hierarchy from one executable in another. `Command.exec` takes the file path to an executable that uses the `Command` module and returns a `Command.t` that integrates the executable (by exec'ing it), including providing recursive help and autocompletion as if it were a standard `Command.t`. - Replaced most uses of `Hashtbl.replace` with `Hashtbl.set`. - Renamed `Float.epsilon` to `robust_comparison_tolerance`, to avoid confusion with `epsilon_float`. ## 111.25.00 - Added `Gc.disable_compaction` function. - Added `Time.to_string_abs_trimmed`, which prints a trimmed time and takes a `zone` argument. - Fixed `unix_stubs.c` to suppress a warning when building with some versions of gcc. - Changed `Time.Zone` to allow the zoneinfo location to be specified by an environment variable. Closes #40 - Fix compatibility with 4.02 ## 111.21.00 - Fixed an issue where `Time.Zone.init` would not properly traverse the directory containing timezone information. - Added `Time.With_utc_sexp`, which has stable serialization of `Time.t` that is byte-for-byte equal across timezones. - Made `Uuid` stable. - Made `Piecewise_linear` stable. ## 111.17.00 - Fixed a bug in `Bigstring.really_recv` if `recv` doesn't receive all the data it wants. This bug has been around forever; it may not have caused trouble because `Bigstring.really_recv` (1) is barely used (the only use is in `Bigstring.unmarshal_from_sock`) and (2) passes `recv` the `MSG_WAITALL` flag, so it will read the full amount unless it gets interrupted by a signal. - Fixed `Bigstring.read`'s handling of `EINTR` so that it retries rather than returning zero. This fixes a bug introduced in 111.09 in the interaction between `Bigstring.read` and `Async.Reader`. Prior to 111.09, `Bigstring.read` would raise on `EINTR`, and `Async.Reader` would propagate the exception. From 111.09 to 111.16, `Bigstring.read` would return zero, which would confuse `Async.Reader` into thinking it reached EOF when it hadn't. From 111.17, `Bigstring.read` will retry and not return zero when not at EOF. We believe the bug was rare, because otherwise we would have frequently seen `EINTR` exceptions prior to 111.09. - Added `Command.Spec.apply` and `pair`, which allow one to program more with `Spec.param` rather than `Spec.t`. ```ocaml val apply : ('a -> 'b) param -> 'a param -> 'b param val pair : 'a param -> 'b param -> ('a * 'b) param ``` - Added `Command.Spec.file`, which builds an `Arg_type` value with the same autocompletion as `Spec.file`. ```ocaml (** [file] defines an [Arg_type.t] that completes in the same way as [Command.Spec.file], but perhaps with a different type than [string] or with an autocompletion key. *) val file : ?key:'a Univ_map.Multi.Key.t -> (string -> 'a) -> 'a t ``` ## 111.11.00 - Change some `Bigstring` functions to retry on `EINTR` rather than raise. The following functions (and their unsafe versions) were affected: * `read` * `really_read` * `really_recv` * `really_write` * `really_send_no_sigpipe` Some other `Bigstring` functions, like `input` and `output`, already retried on `EINTR`, so this change has precedent. All of the affected stubs raise `Bigstring.IOError` on failure, rather than `Unix_error`, which means the normal method for retrying on `EINTR` doesn't work. In particular `Async.Reader` didn't retry them, even though it was supposed to. Additionally, the documentation for the following functions was corrected to say that they raise =Unix_error= rather than =IOError=: * `pread_assume_fd_is_nonblocking` * `pwrite_assume_fd_is_nonblocking` - Eliminated global binary-to-decimal tables computed at startup for converting `Date` and `Of_day` to string. Used an efficient implementation of division by 10, rather than the `sprintf` tables in `time_internal.ml`. This result in much less allocation at startup and it is a bit faster: * before: | Name | Time/Run | mWd/Run | Percentage | |----------------|----------|---------|------------| | Date.to_string | 69.39ns | 3.00w | 100.00% | - after: | Name | Time/Run | mWd/Run | Percentage | |----------------|----------|---------|------------| | Date.to_string | 53.38ns | 3.00w | 100.00% | - Fixed `Time.Zone` tests so that they are deterministic. - Added `Iobuf.to_string_hum`, which produces a readable, multi-line representation of an iobuf, intended for debugging. - Fixed brittle unit tests of `Command`. ## 111.08.00 - Improved `Command` to print a good error message if command-line parsing raises. `Command`'s `Exn.handle_uncaught` now protects the phase of parsing command-line arguments in addition to protecting the phase of running the `main` function as it did already. ## 111.06.00 - Added inline benchmarks for =Iobuf= and =Time=. Hera are some of the results from the new benchmarks, with some indexed tests dropped. | Name | Time/Run | mWd/Run | Percentage | |--------------------------------------|----------|---------|------------| | [time.ml:Time] Time.to_string | 848.74ns | 249.98w | 100.00% | | [time.ml:Time] Time.to_ofday | 59.66ns | 38.00w | 7.03% | | [time.ml:Time] Time.now | 39.78ns | 2.00w | 4.69% | | [time.ml:Time] Time.Zone.find_office | 83.64ns | 4.00w | 9.85% | | [time.ml:Time] Time.Span.of_hr | 3.71ns | 2.00w | 0.44% | | [time.ml:Time] Time.Span.of_min | 3.69ns | 2.00w | 0.44% | | [time.ml:Time] Time.Span.of_sec | 2.72ns | | 0.32% | | [time.ml:Time] Time.Span.of_ms | 6.02ns | 2.00w | 0.71% | | [time.ml:Time] Time.Span.of_ns | 5.98ns | 2.00w | 0.71% | | Name | Time/Run | Percentage | |------------------------------------------|----------|------------| | [iobuf.ml:Blit tests] functor blit:5 | 15.53ns | 7.66% | | [iobuf.ml:Poke tests] char:0 | 4.11ns | 2.03% | | [iobuf.ml:Poke tests] uint8:0 | 5.35ns | 2.64% | | [iobuf.ml:Poke tests] int8:0 | 4.59ns | 2.26% | | [iobuf.ml:Poke tests] int16_be:0 | 5.19ns | 2.56% | | [iobuf.ml:Poke tests] int16_le:0 | 5.14ns | 2.53% | | [iobuf.ml:Poke tests] uint16_be:0 | 5.11ns | 2.52% | | [iobuf.ml:Poke tests] uint16_le:0 | 5.12ns | 2.53% | | [iobuf.ml:Poke tests] int32_be:0 | 5.17ns | 2.55% | | [iobuf.ml:Poke tests] int32_le:0 | 4.91ns | 2.42% | | [iobuf.ml:Poke tests] uint32_be:0 | 5.73ns | 2.83% | | [iobuf.ml:Poke tests] uint32_le:0 | 5.74ns | 2.83% | | [iobuf.ml:Poke tests] int64_be:0 | 5.33ns | 2.63% | | [iobuf.ml:Poke tests] int64_le:0 | 4.93ns | 2.43% | | [iobuf.ml:Peek tests] char:0 | 5.50ns | 2.71% | | [iobuf.ml:Peek tests] uint8:0 | 4.68ns | 2.31% | | [iobuf.ml:Peek tests] int8:0 | 4.91ns | 2.42% | | [iobuf.ml:Peek tests] int16_be:0 | 5.19ns | 2.56% | | [iobuf.ml:Peek tests] int16_le:0 | 4.90ns | 2.42% | | [iobuf.ml:Peek tests] uint16_be:0 | 5.17ns | 2.55% | | [iobuf.ml:Peek tests] uint16_le:0 | 5.10ns | 2.51% | | [iobuf.ml:Peek tests] int32_be:0 | 5.17ns | 2.55% | | [iobuf.ml:Peek tests] int32_le:0 | 4.92ns | 2.42% | | [iobuf.ml:Peek tests] uint32_be:0 | 5.45ns | 2.69% | | [iobuf.ml:Peek tests] uint32_le:0 | 5.46ns | 2.69% | | [iobuf.ml:Peek tests] int64_be:0 | 6.61ns | 3.26% | | [iobuf.ml:Peek tests] int64_le:0 | 6.31ns | 3.11% | - Re-implemented `Thread_safe_queue` to improve performance and reduce allocation. The new implementation requires 3 words per element, down from the 7 words required by the old implementation. The new implementation pools elements so that they can be reused, so there is no allocation in steady-state use. The new implementation has `dequeue_exn` rather than `dequeue`, so that one can dequeue without allocating 2 words. Eliminated `create'`. One should just use `create` and explicit calls to `enqueue` and `dequeue_exn`. Eliminated `dequeue_until_empty`. One should use an explicit while loop guarded by `length` and using `dequeue_exn`. Moved `Thread_safe_queue` from `Core_kernel` to `Core`, since it's thread related. All in, there is now no allocation in a steady-state usage of enqueueing and dequeueing elements, as opposed to 9 words per `enqueue+dequeue` in the old implementation. This reduces the cost from `enqueue+dequeue` taking 166-216ns to `enqueue+dequeue_exn` taking 48-82ns (plus eliminating gc impacts). Here are some `BENCH` results, the first table being the old implementation, and the second table the new. | Name | Time/Run | mWd/Run | mjWd/Run | |------------------------------------------------------------|----------|---------|----------| | [thread_safe_queue.ml] enqueue + dequeue of immediate | 183.89ns | 9.00w | 7.02w | | [thread_safe_queue.ml] enqueue + dequeue of young object | 216.69ns | 11.00w | 9.01w | | [thread_safe_queue.ml] enqueue + dequeue_exn of old object | 166.75ns | 9.00w | 7.02w | | Name | Time/Run | mWd/Run | |--------------------------------------------------------------|----------|---------| | [thread_safe_queue.ml] enqueue + dequeue_exn of immediate | 48.20ns | | | [thread_safe_queue.ml] enqueue + dequeue_exn of young object | 81.96ns | 2.00w | | [thread_safe_queue.ml] enqueue + dequeue_exn of old object | 48.30ns | | - Changed `{Bigstring,Iobuf}.recvmmsg_assume_fd_is_nonblocking`, when no message is available, to return a negative number rather than raise. This was done for performance reasons, because raising an exception is expensive, due to the stashing of the backtrace and the string creation. - Added `Iobuf.unsafe_resize`. - Changed `Bigstring.blit` so that it doesn't release the OCaml lock on `map_file` bigstrings. The old behavior of releasing the lock for blits of (small) bigstrings involving mmapped files was problematic and inconsistent. Its cost is high, and fundamentally any access to a mapped bigstring could cause some level of blocking. - Added time-related `Arg_type.t` values to `Command.Spec`. - Added module `Type_immediacy`, which has witnesses that express whether a type's values are always, sometimes, or never immediate. This code used to be in the `Typerep_immediate` library in typerep. ## 111.03.00 - Added `Unix.Syslog` module. - Changed `Command.run` to no longer ignore the first element of its `~argv` parameter. - Made `Time.Span.to_short_string` show microsecond precision. ## 110.01.00 - Fixed `Time` unit tests that failed in London because of timezone dependence. - Added `Iobuf.protect_window_and_bounds`, which calls a user function and restores the iobuf's bounds afterwards. - Fixed compilation on OpenBSD, which doesn't support `Unix.mcast_join`'s `?source : Inet_addr.t` argument. ## 109.60.00 - Added `Iobuf.unsafe_advance`. This can be used to benchmark inner loops that have redundant bounds checking, to see if the checks matter. For example, see the following two `advance` calls: let rec process_buffer buf ~f = let len = Iobuf.length buf in if header_len <= len then let msg_len = header_len + Iobuf.Unsafe.Peek.uint16_be buf ~pos:0 in if msg_len <= len then begin let len = msg_len - header_len in Iobuf.advance buf header_len; f (Protocol.packed_of_iobuf buf); Iobuf.advance buf len; process_buffer buf ~f end - Added `Weak_hashtbl.add_exn` and `sexp_of_t`. - Fixed `Lock_file.create` to behave correctly if the target mountpoint is out of space. Previously in this situation, `Lock_file.create` would create an empty lock and exit with exception trying to write pid/message there. Subsequent runs would not able to read pid out of empty pid file and `blocking_create` would block instead of removing defective lock. ## 109.58.00 - Added `Debug.should_print_backtrace : bool ref`, to control whether `Debug.am*` functions print backtraces. - Added to `Float` inline benchmarks. - Moved all of the `Gc` module into `Core_kernel`. Part of the `Gc` module used to be in `Core` because it used threads. But it doesn't use threads anymore, so can be all in `Core_kernel`. - Improved `Iobuf` support for copying to/from strings and bigstrings. The new modules are `Iobuf.{Consume,Peek}.To_{bigstring,string}`. They match a `Blit`-like interface. We don't yet implement the `Blit` interface in all applicable contexts, but do use `Blit.Make` and expose some of the operations we want in the forms we expect them to take under a `Blit` interface. - Added `Linux_ext.Timerfd.to_file_descr`. - Added to `Time.next_multiple` an optional argument to control whether the inequality with `after` is strict. - Added `Time.Zone.local`, a lazily cached `Time.Zone.machine_zone ()`. This is the first stage in a plan to make explicit timezones more pervasive. First, they are made more convenient, by replacing the relatively wordy `Time.Zone.machine_zone ()` with `Time.Zone.local`. This involves making the underlying timezone type lazy. The next stage will be to remove `machine_zone` and use `Time.Zone.local` everywhere instead. Then (it is hoped) instead of `of_local_whatever`, we just say e.g. `of_date_ofday Time.Zone.local` and currently-implicitly-local functions will be able to switch over to explicit timezones without becoming too verbose. - Added `Timing_wheel.Alarm.null`. - Made `Unix.File_descr.t` have `with sexp`. Closes janestreet/async_unix#3 - Fixed OpenBSD compilation failures in C stubs. - Fixed `Lock_file.is_locked` to require read permission, not write permission, on the lock file. - Added to `Unix.mcast_join` an optional `?source:Inet_addr.t` argument. From pull-request on bitbucket: https://bitbucket.org/janestreet/core/pull-request/1/receive-source-specific-multicast/diff ## 109.55.00 - Fixed building on FreeBSD and OpenBSD. - Added `with typerep` to many `Core` types. - Made `open Core.Std` support `with typerep`. - Added `Iobuf.recvmmsg_assume_fd_is_nonblocking_no_options`, a specialization of `recvmmsg_assume_fd_is_nonblocking` for improved performance. This improvement was driven by profiling at high message rates. - Changed `Unix.Rlimit.virtual_memory` be an `Or_error.t`, for platforms where it is undefined. ## 109.53.00 - Added `Linux_ext.Epoll.close`. - Added `Weak_hashtbl` module, moved from `Async`. It had only been in `Async` to use `Async`'s finalizers. The move to `Core` exposes a bit more with respect to finalization so that one can still implement `Async.Weak_hashtbl`, as well as do other things (e.g. use `Weak_hashtbl` in `Incremental`, which does not use `Async`). Simplified the implementation of `Weak_hashtbl` to eliminate "entry ids". They were only used to avoid removing a table entry that was in use. But there is a more direct way to test for that -- just check if the weak is `None` or `Some`. - Added an autoload file for utop - Disabled warning 40 in corebuild ## 109.52.00 - Added `Unix.File_descr.equal`. - Added `Lock_file.Nfs.unlock`, the `Or_error` version of `unlock_exn`. - Improved the detail of the error messages exposed by `Lock_file.Nfs.create{,_exn}`. - Added `Unix.set_mcast_ifname`, to control the interface used for UDP multicast traffic. Added bindings for setsockopt `IP_MULTICAST_IF`. See 6.3 in: http://www.tldp.org/HOWTO/Multicast-HOWTO-6.html - Changed `Command` argument processing to treat a single dash (`-`) as an anonymous argument rather than a flag. This change follows the unix convention of passing `-` as an anonymous argument meaning `stdin`. - Added more bin-prot support to `Iobuf`: `Consume.bin_prot`, `Fill.bin_prot`, `Peek.bin_prot`, `Poke.bin_prot`. Framing doesn't do much for `Iobuf`, so these are to be more standard, unframed accessors, as opposed to `fill_bin_prot`. - Added `Core.Debug.am`, `amf`, and `ams`, for outputting debugging messages showing the current source-code position. Unfortunately, these aren't available in `Core.Std.Debug`, but only in `Core.Debug`. That will be fixed in 109.49. - Made `Time_stamp_counter` compile on non x86-64 platforms. - Made `Core.Std.Debug` be `Core.Debug` rather than `Core_kernel.Debug`. This exposes the `Debug.am*` functions added in 109.48. ## 109.47.00 - Added `Time_stamp_counter` module, which has fast (< 10 nanos) access to the hardware time-stamp counter. This module provides the fast function `Time_stamp_counter.now ()` which is our best effort high-performance cycle counter for a given platform. For x86 systems this retrieves the CPU's internal time stamp counter using the `RDTSC` instruction. For systems that do not have a RDTSC instruction, we fallback to using `clock_gettime(CLOCK_MONOTONIC)`. Here is a benchmark of execution time in nanos and allocations in words: ``` Name Time/Run Minor ------------------------------- ---------- ------- Time.now 39.02 2.00 TSC.now 7.54 TSC.to_time 4.88 2.00 TSC.to_time (TSC.now ()) 8.54 2.00 TSC.to_time_nanos 4.49 TSC.to_time_nanos(TSC.now ()) 8.95 Calibrator.calibrate 279 34.00 ``` Historically, the rate of increment of the TSC (sometimes referred to as the TSC frequency) varied based of CPU overclocking, temperature, load etc. On modern Intel CPU's the TSC is expected to be stable. On Linux systems, the "constant_tsc" in `/proc/cpuinfo` indicates that the machine has a stable TSC rate. While this module assumes that the TSC is relatively stable, it can adapt to small variations in the TSC frequency. - Changed `Daemon.daemonize` and `daemonize_wait` to leave the `umask` alone by default. Previously, these had alwasy set the umask to `0`, which means that all app-harness programs and all binaries run from grass were creating world-writeable (`0666`) files by default. ## 109.45.00 - Added `Core.Std.phys_same`, which is like `phys_equal`, except has a more general type. ```ocaml val phys_equal : 'a -> 'a -> bool val phys_same : _ -> _ -> bool ``` `phys_same` is useful when dealing with existential types, and one has a packed value and an unpacked value that one wants to check are physically equal. One can't use `phys_equal` in such a situation because the types are different. - Added `Iobuf.set_bounds_and_buffer` and `set_bounds_and_buffer_sub`, which make it easier to use with zero allocation. ```ocaml (** [set_bounds_and_buffer ~src ~dst] copies bounds (ie limits + window) and shallowly copies the buffer from [src] to [dst]. [read_write] access is required on [src] because the caller might have [read_write] access to [dst], and would after the call then effectively have [read_write] access to [src]. *) val set_bounds_and_buffer : src:(read_write, _) t -> dst:(_, seek) t -> unit (** [set_bounds_and_buffer_sub ?pos ?len ~src ~dst ()] is a more efficient version of: [set_bounds_and_buffer ~src:(Iobuf.sub ?pos ?len src) ~dst]. [set_bounds_and_buffer ~src ~dst] is not the same as [set_bounds_and_buffer_sub ~dst ~src ()], because the limits are narrowed in the latter case. *) val set_bounds_and_buffer_sub : ?pos:int -> ?len:int -> src:(read_write, _) t -> dst:(_, seek) t -> unit -> unit ``` - Added `?timeout:Time.Span.t` argument to `Lock_file.blocking_create`, `Lock_file.Nfs.blocking_create` and `critical_section`. ## 109.44.00 - Added `val Day_of_week.num_days : from:t -> to_:t -> int`. - Added `Time.of_date_ofday_precise` and `Time.Zone.next_clock_shift`, to deal with clocks going forward and backward. Due to clocks going forward/backward, some local times occur twice, and some never occur at all. `Time.of_date_ofday_precise` identifies these cases and returns all of the relevant information. - Added accessors for `Unix.Cidr`: `base_address` and `bits`. ```ocaml (** Accessors. - [base_address 192.168.0.0/24 ` 192.168.0.0] - [bits 192.168.0.0/24 ` 24]. *) val base_address : t -> Inet_addr.t val bits : t -> int ``` ## 109.42.00 - Removed `Zone` from `Core.Std`; use `Time.Zone` instead. - Removed `Time.Date`; use `Date` instead. - Improved the performance of `Piecewise_linear` by using arrays with binary search on indices. The previous implementation `Piecewise_linear` used `(float * float) list` (a list of (x,y) pairs) to represent piecewise linear functions, with a linear search through the knots to evaluate the function at a point. This type is now: ```ocaml { x : float array ; y : float array } ``` and the implementation uses binary search to identify the correct array index. Here are the costs of the `get` function under the old (list) and new (array) implementations for various numbers of knots: ``` knots | old | new ------+------+----- 1 | 11ns| 12ns 2 | 18ns| 14ns 5 | 27ns| 19ns 100 | 182ns| 38ns 1000 |1974ns| 52ns ``` - Added module `Time.Ofday.Zoned`, which is a pair of an `Time.Ofday.t` and a `Time.Zone.t`. - Added `with compare` to `Time.Zone.Stable.t`. - Added `Timing_wheel` functionality. * Added `Config` module, which combines `alarm_precision` and `timing_wheel_level_bits`. * Removed the need to supply a dummy value to `create`. * Added `mem` and `clear` functions. * Added functions for dealing with the interval number: `interval_num`, `now_interval_num`, `interval_num_start`, `add_at_interval_num`. This makes it easier to use a timing wheel with `int` interval numbers, which are more efficient than than `float` times. ## 109.41.00 - Added `Command.Spec.map_anon` and `map_flag`. ```ocaml (** [map_flag flag ~f] transforms the parsed result of [flag] by applying [f] *) val map_flag : 'a flag -> f:('a -> 'b) -> 'b flag (** [map_anons anons ~f] transforms the parsed result of [anons] by applying [f] *) val map_anons : 'a anons -> f:('a -> 'b) -> 'b anons ``` - Fixed `Unix.open_flag` to compile with OCaml 4.01. It needed the additional constructor `O_CLOEXEC`. ## 109.37.00 - Command.run now calls Exn.handle_uncaught so you don't have to. - Fixes for building on FreeBSD. - Fixed Blang to build with OCaml 4.01. In blang.mli: Blang.t is a private variant type, Blang.Stable.V1.t is a private variant type, and client code knows Blang.t = Blang.Stable.V1.t. Previously, this was done in a strange way, using with type 'a t = private 'a t on the signature of Blang.Stable.V1. In addition to being strange, this line no longer builds in OCaml 4.01, which caused problems for building Real World Ocaml. This patch changed the code to something much more straightforward, although not quite so straightforward as we expect to be able to achieve once a nonrec bug is fixed. ## 109.35.00 - Added `or_error` functions in `Unix.Exit_*` types to `unit Or_error.t`. This makes it easier to deal with combining with infix operators `>>=?` and `>>|?` ## 109.34.00 - Added `val Backtrace.get_opt : unit -> t option`. This is more convenient to use than `Backtrace.get`, which is an `Or_error.t`. - Moved functions for dealing with finalizers into the `Gc.Expert` module. This was done to make people be very explicit and sure that they want finalizers, which are very hard to use because they essentially introduce multithreading semantics. One should typically use async finalizers. - Eliminated the thread that had been used to sequentialize all finalizers. ## 109.32.00 - Normalized `Command`'s help messages. Made anonymous argument names uppercase and subcommand names lowercase. - In `Iobuf`, added duals to `flip` and `snapshot` to work on the high end of the window. `flip` has been renamed to `flip_lo`. The dual of `flip_lo` is the newly added `flip_hi`, and shifts the window forward to continue reading, rather than back to switch from writing to reading, as `flip_lo` does. `flip_hi`, in practice, needs snapshots of the upper bound of the window, we split `Snapshot` into `Lo_bound` and `Hi_bound` and introduced bounded versions of `flip_lo`, `compact`, and `flip_hi` to support buffers which are only partially filled, but have substructure, like packet buffers. Here's the new API. ```ocaml module type Bound = sig type ('d, 'w) iobuf (** Expose =t = private int= only if a =t= is stored in a mutable data structure somewhere and leads to a measurable =caml_modify= performance problem. *) type t with sexp_of val window : (_, _) iobuf -> t val limit : (_, _) iobuf -> t val restore : t -> (_, seek) iobuf -> unit end module Lo_bound : Bound module Hi_bound : Bound val flip_lo : (_, seek) t -> unit val bounded_flip_lo : (_, seek) t -> Lo_bound.t -> unit val flip_hi : (_, seek) t -> unit val bounded_flip_hi : (_, seek) t -> Hi_bound.t -> unit ``` ## 109.30.00 - Created submodule `Core.Signal.Expert` module. This is for functions previously in `Core.Signal` that introduce multithreading semantics, and are hence hard to reason about and should only be used by experts. ## 109.28.00 - Moved `Timing_wheel` from `Zero`. ## 109.27.00 - Disabled use of `recvmmssg`, which isn't available on our CentOS 5 machines. - Defined `Option.compare` using `with compare` so that their comparisons are consistent. - Cleaned up the `Dequeue` module's interface and implementation. The interface now matches the conventions used elsewhere in `Core`. The new implementation is also cleaner and more efficient. - Reimplemented the `Stack` module to improve performance, and renamed the old implementation as `Linked_stack`. The new `Stack` is implemented with this type: ```ocaml type 'a t ` { dummy : 'a; mutable length : int; mutable elts : 'a array; } ``` `Linked_stack` is implemented with this type: ```ocaml type 'a t ` { mutable length : int; mutable elts : 'a list; } ``` Using an array rather than a linked list is a more efficient and traditional implementation. Pushing to the stack now does not require allocation, except in the rare case when the stack grows. One downside is that `Stack.clear` is now O(n) rather than O(1). This change also eliminates the `Stack.Empty` exception, so any code matching on that exception should fail to compile, and should be changed to depend on option-returning `top` and `pop` operations. - Improved `Lock_file.Nfs`. * Allowed an arbitrary message to be stored and retreived. * Fixed a case where `create` might throw an exception. * Delete both files used for locking when we unlock. - Split `Core` into `Core_kernel` and `Core`. - `Core_kernel` is composed of all modules of `Core` that do not depend on unix or threads, and `Core` contains the rest and depends on `Core_kernel`. The goal is to have a very portable standard library that can especially run on exotic environment such as Javascript. So that code that directly refers to `Core` (rather than `Core.Std`) for modules that have moved to `Core_kernel`, we included "proxy" modules in `Core` that simply include the corresponding module from `Core_kernel`. - Fixed `Core.Flags` to build on 32-bit machines. It had contained a unit test with an integer literal too large to be accepted by the compiler when building on a 32-bit machine. ## 109.24.00 - Added module `Core.Iobuf`, a module aimed at zero-copy I/O. An iobuf is a bigstring combined with a position and length, that defines a contiguous region of bytes in the bigstring. Operations on an iobuf operate relative to start of the region and cannot look outside the region. - Added module `Core.Validated` for creating an abstract type that ensures a validation function has been run. - Added function `Bigstring.recvmmsg_assume_fd_is_nonblocking`, which allows one to read a number of UDP packets with a single system call. - Fixed `Unix.create_process` on OSX. ## 109.23.00 - Exposed `Core.Std.Flags` module. - Made the `Heap` module implement `Container.S1`. - Added module `Ref.Permissioned`, which is a ref with `read_only` / `read_write` access control. - Exposed the unique id in `Type_equal.Id`. This allows, e.g. hash tables indexed by unique ids. - Removed the use of `Obj.magic` from the implementation of `Type_equal.Id.same`. It is not needed because the `Id.t` contains a `Uid.t` and we can just use `Uid.equal`. ## 109.21.00 - Massively improved the signatures of `Map` and `Set`, both for readability and ocamldoc, as well as improved type error messages. For instance the type of `Int.Set.singleton` was: ```ocaml ('a, 'comparator, 'a Core.Std.Int.Set.elt_ -> ('a, 'comparator) Core.Std.Int.Set.t_) Core.Core_set_intf.without_comparator ``` Now it is simply: ```ocaml int -> Int.Set.t ``` - Added an optional argument to `Command.run` that can be used to specify default flags from a user config file. The optional argument can extend the command line based on the path to the command. - Rename module `Weekday` as `Day_of_week`. The name `Weekday` conflicted with ordinary usage of "weekday" to mean Monday through Friday. - Changed `sexp_of_t` for `{Month,Ofday,Time,Time.Span}.{Set,Map}` to use the nice sexp format of the underlying atomic type. Previously, the converter had used thes raw type (`float`, `int`, etc.). `t_of_sexp` still accepts both formats; we will remove the ability to accept the raw format in the distant future. This output-format change was planned when we originally in 108.06b improved those `t_of_sexp` functions to accept both formats. - Added `Unix.remove`. - Removed some `IFDEF`'s connected to OCaml <4 support. ## 109.20.00 - Wrapped `Unix.wordexp` in an `Or_error.t` since it is not available on all systems. - Added function `Process_env.parse_ssh_client`. This gets the address from which you're currently ssh'd in. - Added to `Unix` module the ability to get and set `IP_MULTICAST_LOOP` and `IP_MULTICAST_TTL`. - Exposed module `Core.Std.Ref`, which was previously only available via `Core.Ref`. - Remove `Mutex.am_holding_mutex` and changed the type of `Mutex.try_lock`. With NPTL it is impossible to determine which thread is holding the lock. So, `Mutex.am_holding_mutex` is unimplementable. Also, `Mutex.try_lock` was incorrect because it claimed to raise if one was attempting to recursively lock. Since it's not possible to distinguish between recursive locking and the lock being held by another thread, we changed the type to make this clear: ```ocaml val try_lock : t -> [ `Already_held_by_me_or_other | `Acquired ] ``` - Removed our custom version of the OCaml runtime's `core_sys_open` function. There used to be a bug in the OCaml runtime, PR#5069, in which `open_{in,out}_gen` could block while holding the OCaml lock, because they made a call to `fcntl` outside the blocking section. We had our own C code with the bug fix and re-exposed the fixed versions of the functions in `Core`. The bug in OCaml has been fixed, so we have removed our patched function from `Core`. - In `unix_stubs.c`, switched from using `FNM_FILE_NAME` to `FNM_PATHNAME`. The GNU project introduced FNM_FILE_NAME as a non-portable synonym for FNM_PATHNAME. We were using pre-processor macros to define FNM_FILE_NAME as FNM_PATHNAME if unavailable, but it is simpler to just use the more portable FNM_PATHNAME everywhere. ## 109.19.00 - Changed `Time.to_string` and `Time.sexp_of_t` to include the timezone. This is an incompatible change with very old programs in which `Time.of_string` and `Time.t_of_sexp` did not support the timezone. If you have programs that are: * very old and do Time string/sexp handling * rely on reading in time values without using `Time.of_string` and `Time.t_of_sexp`. * rely on chains of writing/reading/writing times across machines and timezones where the time is always intended to be taken as the local time on the currently reading machine you should recompile/review your code to make sure you won't have issues. - Added function `List.remove_consecutive_duplicates : 'a t -> equal:('a -> 'a -> bool) -> 'a t`. This returns the input list with consecutive duplicates removed, and doesn't change the order of the remaining elements. - Added module `User_and_group`, which is a pair of a unix username and primary unix group. The string/sexp converters follow the usual unix convention of `:`. - Added function `Date.first_strictly_after : t -> on:Weekday.t -> t`. `first_strictly_after t ~on:day_of_week` returns the first occurrence of `day_of_week` strictly after `t`. - Added functor `Type_equal.Lift`. It is always safe to conclude that if type `a` equals `b`, then type `a X.t` equals `b X.t`, for any type `X.t`. The OCaml type checker uses this fact when it can. However, sometimes, e.g. when using `Type_equal.conv`, one needs to explicitly use this fact to construct an appropriate `Type_equal.t`. The `Type_equal.Lift*` functors do this. ```ocaml module Type_equal : sig type ('a, 'b) t ... module Lift (X : T1) : sig val lift : ('a, 'b) t -> ('a X.t, 'b X.t) t end end ``` ## 109.18.00 - changed implementation of `Array.sort` to use introsort. See http://en.wikipedia.org/wiki/Introsort. - tweaked a unit test in `Core.Flags` to not print a message to stderr. ## 109.17.00 - Fixed `Random.self_init`, which was broken since 109.00.00 with the upgrade to OCaml 4.0 The fix changed the type signature expressed in `core_random.ml` of the standard OCaml `caml_sys_random_seed` C function from `unit -> int` from `unit -> int array`. That C function changed between OCaml 3.12 and 4.0. - Moved module `Core_extended.Unix.Cidr` into `Core.Unix`. - Wrapped `Unix.wordexp` into an `Or_error.t` to handle systems that does not implement it in the libc. - Fixed two other printer names - Added `Array.int_blit` and `Array.float_blit`, which are specialized fast blits for `int array` and `float array`. For motivation underlying this change and other design alternatives please see Section 3 "Fast, Slow and Incorrect Array blits" of http://janestreet.github.com/ocaml-perf-notes.html - Added `Unpack_buffer.Unpack_one.sexp` for parsing sexps using the `Unpack_buffer` interface. ## 109.15.00 - Changed the tolerance of `Time.Robustly_compare` functions from `1E-7` to `1E-6`. - Fixed the names of some toplevel pretty-printers, which referred to nonexistent modules. Fix some of the `pp`'s for Core which are used to install printers in the top-level. Some of the toplevel printers refer to non-existent modules like `Core.Nativeint.pp`; this feature changed to the correct name, like `Core.Std.Nativeint.pp`. - Added to module `Unix` functionality for getting and setting flags in the open-file-descriptor table. ```ocaml module Open_flags : sig type t include Flags.S with type t :` t ... end val fcntl_getfl : File_descr.t -> Open_flags.t val fcntl_setfl : File_descr.t -> Open_flags.t -> unit ``` - Added module `Linux_ext.Timerfd`. This allows one to create a file descriptor that can be monitored by `epoll` or `select` and notify them at a certain time. It makes it possible to use `epoll` with sub-millisecond timeouts. - Added `Version_util.application_specific_fields`, which allows custom build-time information to be included in an executable. ## 109.14.00 - Fixed major performance problem with hashing in `Int.Table`. Our `Int.Table.replace` was 3 times slower than polymorphic hash table and `find` was _8_ times slower. This was caused by using: ```ocaml external seeded_hash_param : int -> int -> int -> 'a -> int = "caml_hash" "noalloc" ``` in `Int.Table` but: ```ocaml external old_hash_param : int -> int -> 'a -> int = "caml_hash_univ_param" "noalloc" ``` everywhere else. The `seeded_hash_param` was introduced in Caml 4. We fixed this problem by changing `Int.hash` from: ```ocaml let hash (x : t) = Hashtbl.hash x ``` to: ```ocaml let hash (x : t) = if x >= 0 then x else ~-x ``` - Added `Bigstring.{pread,pwrite}`, which allow reading and writing at a specific file offset. - Added module `Nothing`, which is a type with no values. This is useful when an interface requires you to specify a type that you know will never be used in your implementation. - Changed `Identifiable.Make` so that it registers a pretty printer. `Identifiable.Make` now uses `Pretty_printer.Register`. This requires all calls to `Identifiable.Make` to supply a `val module_name : string`. - Made `Core.Zone` match the `Identifiable` signature. - Made polymorphic equality always fail on `Core.Map.t` and `Core.Set.t`. Before this change, polymorphic equality on a `Core.Map` or a `Core.Set` could either raise or return `false`. It returnd `false` if the data structures were unequal, and raised if the data structures were equal. This is because their type definitions looked like: ```ocaml type ('k, 'v, 'comparator) t = { tree : ('k, 'v) Tree0.t; comparator : ('k, 'comparator) Comparator.t; } ``` and polymorphic equality visits a block's fields in order. So, it will detect unequal trees and return false, but if the trees are equal, it will compare the comparators and raise because of the functional value. This change reversed the order of the fields so polymorphic equality always fails. ## 109.13.00 - Added `Command.Spec.flags_of_args_exn`, for compatibility with OCaml's standard library. This function converts a `Core.Std.Arg.t` into a `Command.Spec.t`. - Made various modules `Identifiable`: `Char`, `String`, and the various `Int` modules. In particular, `Int` being identifiable is useful, because one can now write: ```ocaml module My_numeric_identifier : Identifiable ` Int ``` You might think that we could now delete `String_id`, and just write: ```ocaml module My_string_identifier : Identifiable ` String ``` But this is not quite equivalent to using `String_id`, because `String_id.of_string` enforces that its argument is nonempty. - Removed module `Space_safe_tuple`, which became unnecessary in OCaml 4.00.0. OCaml 4.00.0 included Fabrice's patch to fix the space leak that `Space_safe_tuple` was circumventing (PR#5288, commit SVN 11085). - Added `Exn.to_string_mach`, for single-line output. - Added `Linux_ext.bind_to_interface`, to improve security of UDP applications. ```ocaml val bind_to_interface : (File_descr.t -> string -> unit) Or_error.t ``` This uses the linux-specifc socket option `BINDTODEVICE` to prevent packets being received from any interface other than one named. - Fixed `Unix.mkdir_p` on Mac OS X. ## 109.12.00 - Add some functions to `Byte_units`. - Added functions: `to_string_hum`, `scale`, `Infix.//`. - Eliminated the notion of "preferred measure", so a `Byte_units.t` is just a `float`. - Improved the performance of `Array.of_list_rev`. The new implementation puts the list elements directly in the right place in the resulting array, rather that putting them in order and then reversing the array in place. Benchmarking shows that the new implementation runs in 2/3 the time of the old one. - Fixed `Fqueue.t_of_sexp`, which didn't work with `sexp_of_t`. There was a custom `sexp_of_t` to abstract away the internal record structure and make the sexp look like a list, but there wasn't a custom `t_of_sexp` defined, so it didn't work. - Added `Stable.V1` types for `Host_and_port`. - Removed `Identifiable.Of_sexpable` and `Identifiable.Of_stringable`, in favor of `Identifiable.Make` `Identifiable.Of_sexpable` encouraged a terrible implementation of `Identifiable.S`. In particular, `hash`, `compare`, and bin_io were all built by converting the type to a sexp, and then to a string. `Identifiable.Of_stringable` wasn't as obviously bad as `Of_sexpable`. But it still used the string as an intermediate, which is often the wrong choice -- especially for `compare` and `bin_io`, which can be generated by preprocessors. Added `Identifiable.Make` as the replacement. It avoids using sexp conversion for any of the other operations. - Added `List.intersperse` and `List.split_while`. These came from `Core_extended.List`. ```ocaml val intersperse : 'a list -> sep:'a -> 'a list val split_while : 'a list -> f:('a -> bool) -> 'a list ** 'a list ``` - Added a functor, `Pretty_printer.Register`, for registering pretty printers. The codifies the idiom that was duplicated in lots of places: ```ocaml let pp formatter t = Format.pp_print_string formatter (to_string t) let () = Pretty_printer.register "Some_module.pp") ``` ## 109.11.00 - Added module `Interned_string` This has a functor for creating modules of interned strings. It uses the very simple mechanism of mapping distinct strings to consecutive ints. - Added value `Hashtbl.find_and_remove`. ## 109.10.00 - Added `|>`, which means the same as `|!`, but is likely to replace it someday. This is mostly because `|>` is an accepted notation elsewhere, particularly in F#. In the future, we will consider eliminating `|!` in favor of `|>`, so as to avoid the duplication. - Made `module Lazy` into a monad. - Renamed `List.stable_dedup_involving_an_application_of_the_set_functor` as `List.stable_dedup_staged`. Made it use `Staged.t` to make explicit the expectation of partial application. - Added pretty printers for the toplevel to `Error` and `Info`. ## 109.09.00 - In `Core.Std`, exposed `Or_error.ok_exn` and `Or_error.error` - Removed some values exported by `Core.Std`. Removed some values from `Core.Std` that weren't widely used, or we didn't think should be exposed, including `ascending`, `descending`, and `equal`, which use polymorphic comparison, and we want to discourage. Here's a guide to some of what was removed, and what one should now use instead. | removed | replace with | |-----------------------------------+---------------------------------------| | `Int_replace_polymorphic_compare` | `Int.Replace_polymorphic_compare` | | `ascending` | `Polymorphic_compare.ascending` | | `descending` | `Polymorphic_compare.descending` | | `equal` | `Polymorphic_compare.equal` | | `ifprintf` | `Printf.ifprintf` | | `sscanf` | `Scanf.sscanf` | | `Scan_failure` | `Scanf.Scan_failure` | | `string_of__of__sexp_of` | `Sexplib.Conv.string_of__of__sexp_of` | | `of_string__of__of_sexp` | `Sexplib.Conv.of_string__of__of_sexp` | | `type vec` | `type float64_vec` | - Disallowed `<:sexp_of<` with two underscores; using a single underscore instead. - Added `Command.Spec.Arg_type.of_alist_exn` as an alternative for `of_map`. This captures the common pattern to create the map from an alist. - Improved the performance of `Hashtbl`. Constrained hashtbl size to a power of two and used a bitmask rather than mod operation for finding hash buckets. - Improved the performance of `Univ`, using the `Type_equal` GADT. The new implementation improves the run-time and space usage over the old one. In the old implementation, a `Univ.t` was represented as record with three fields: an exception, a string, and a closure. Creating a univ required allocating three heap blocks, the exception (3 words), the closure (3 words), and the three-field record (4 words). In the new implementation, a `Univ.t` is represented as a 2-field heap block containing the `Constr.t` and the value. Creating a univ allocates that single 3-word block, improving on the 10 words needed previously. Matching on univs is also faster. In the old implementation, matching on a univ required making a function call, testing exception equality, and allocating a `Some` block. Now, it does just the test and allocation. Furthermore, it is possible to use `does_match` and `match_exn` to avoid the allocation. - Added `Version_util.build_info_as_sexp`. - Added `_squelch_unused_module_warning_` to `Comparable.S.Replace_polymorphic_compare`. ## 109.08.00 - Cleaned up and updated the `README`. - Changed executables to enable backtraces if `OCAMLRUNPARAM` is not set. - Changed `Command` so that executables show build info and version info This happens when an executatble is called as: foo.exe version Before this change, rather than display build info, executables would display the not-so-helpful: (no option given - printing version) - Added back `Float` rounding functions with a hardcoded direction. - Exposed `with bin_io` and `with compare` for the =sexp_bool= type. - Added value `Core.Never_returns.sexp_of_t`. - Added values `Or_error.tag{,_arg}` These are analogous to `Error` functions of the same name. - Added functor `Sexpable.Of_sexpable` This is for serializing values of one type as though it were some other isomorphic type. - Added module `Backtrace.Exn` This exposes OCaml stdlib's `Printexc` functions for backtraces. - Added module `Flags` This implements Unix-style sets of flags that are represented as an `int` with various bits set, one bit for each flag, e.g., `Linux_ext.Epoll.Flag`. - Added module `Uuid` This module implements universally unique identifiers based on version 3 of the UUID specification. It used to be in `Core_extended=` - Added module `Type_equal`, which defines the "equality" GADT. ## 109.07.00 - Added a number of functions to =Bounded_int_table=: =equal=, =exists{,i}=, =for_all{,i}=, =filter_map{,i}=, =map{,i}=. Also added a functor, =Bounded_int_table.With_key=, that makes a bounded-int table binable and sexpable, and adds =of_alist= and =of_alist_exn=. - Added =Doubly_linked.iter_elt= and =Bag.iter_elt=. - Added =module Invariant=, which defines signatures that are to be included in other signatures to ensure a consistent interface to invariant-style functions. - Added =module Ordering=, which defines: =type t = Less | Equal | Greater= ## 109.06.00 - Added [Map.symmetric_diff], for returning a list of differences between two maps. It has a fast-path implementation for maps that share a large amount of their internal structure. ## 109.05.00 - Updated [Core.Unix.stat] so that access, modify, and change times have nanosecond precision. - Fixed a bug in [Nano_mutex.invariant]. - Simplified the implementation of [with_return] using a local explicit polymorphic type variable. ## 109.04.00 - Fix [Backtrace.get], which was broken in 109.00, with the switch to OCaml 4.0. - Added [Heap.iter_el]. ## 109.02.00 - Add Char.of_string core-113.00.00/COPYRIGHT.txt000066400000000000000000000005101256461075500150640ustar00rootroot00000000000000Copyright (C) 2008- Jane Street Group, LLC 1 New York Plaza, 33rd Floor New York, NY 10004 USA email: opensource@janestreet.com The contents of some files in this distribution was derived from external sources with compatible licenses. The original copyright and license notice was preserved in the affected files. core-113.00.00/INRIA-DISCLAIMER.txt000066400000000000000000000013321256461075500157730ustar00rootroot00000000000000THIS SOFTWARE IS PROVIDED BY INRIA AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INRIA OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. core-113.00.00/INSTALL.txt000066400000000000000000000026531256461075500146340ustar00rootroot00000000000000(* OASIS_START *) (* DO NOT EDIT (digest: b9e5e533fd87466bbc85d04e3f99e749) *) This is the INSTALL file for the core distribution. This package uses OASIS to generate its build system. See section OASIS for full information. Dependencies ============ In order to compile this package, you will need: * ocaml (>= 4.00.1) for all, test test_runner * findlib (>= 1.3.2) * bin_prot for library core * comparelib for library core * core_kernel for library core * custom_printf for library core * enumerate for library core * fieldslib for library core * herelib for library core * pa_bench for library core * pa_ounit for library core * pa_pipebang for library core * pa_structural_sexp for library core * pa_test for library core * sexplib for library core * sexplib_unix for library core * typerep_lib for library core * variantslib for library core * compiler-libs for library core_top * oUnit (>= 1.0.2) for executable test_runner Installing ========== 1. Uncompress the source archive and go to the root of the package 2. Run 'ocaml setup.ml -configure' 3. Run 'ocaml setup.ml -build' 4. Run 'ocaml setup.ml -install' Uninstalling ============ 1. Go to the root of the package 2. Run 'ocaml setup.ml -uninstall' OASIS ===== OASIS is a program that generates a setup.ml file using a simple '_oasis' configuration file. The generated setup only depends on the standard OCaml installation: no additional library is required. (* OASIS_STOP *) core-113.00.00/LICENSE.txt000066400000000000000000000261361256461075500146120ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. core-113.00.00/MLton-license.txt000066400000000000000000000025041256461075500161720ustar00rootroot00000000000000This is the license for MLton, a whole-program optimizing compiler for the Standard ML programming language. Send comments and questions to MLton@mlton.org. MLton COPYRIGHT NOTICE, LICENSE AND DISCLAIMER. Copyright (C) 1999-2009 Henry Cejtin, Matthew Fluet, Suresh Jagannathan, and Stephen Weeks. Copyright (C) 1997-2000 by the NEC Research Institute Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both the copyright notice and this permission notice and warranty disclaimer appear in supporting documentation, and that the name of the above copyright holders, or their entities, not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. The above copyright holders disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness. In no event shall the above copyright holders be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. core-113.00.00/Makefile000066400000000000000000000025121256461075500144170ustar00rootroot00000000000000# Generic Makefile for oasis project # Set to setup.exe for the release SETUP := setup.exe # Default rule default: build # Setup for the development version setup-dev.exe: _oasis setup.ml grep -v '^#' setup.ml > setup_dev.ml ocamlfind ocamlopt -o $@ -linkpkg -package ocamlbuild,oasis.dynrun setup_dev.ml || ocamlfind ocamlc -o $@ -linkpkg -package ocamlbuild,oasis.dynrun setup_dev.ml || true rm -f setup_dev.* # Setup for the release setup.exe: setup.ml ocamlopt.opt -o $@ $< || ocamlopt -o $@ $< || ocamlc -o $@ $< rm -f setup.cmx setup.cmi setup.o setup.obj setup.cmo build: $(SETUP) setup.data ./$(SETUP) -build $(BUILDFLAGS) doc: $(SETUP) setup.data build ./$(SETUP) -doc $(DOCFLAGS) test: $(SETUP) setup.data build ./$(SETUP) -test $(TESTFLAGS) all: $(SETUP) ./$(SETUP) -all $(ALLFLAGS) install: $(SETUP) setup.data ./$(SETUP) -install $(INSTALLFLAGS) uninstall: $(SETUP) setup.data ./$(SETUP) -uninstall $(UNINSTALLFLAGS) reinstall: $(SETUP) setup.data ./$(SETUP) -reinstall $(REINSTALLFLAGS) clean: $(SETUP) ./$(SETUP) -clean $(CLEANFLAGS) distclean: $(SETUP) ./$(SETUP) -distclean $(DISTCLEANFLAGS) configure: $(SETUP) ./$(SETUP) -configure $(CONFIGUREFLAGS) setup.data: $(SETUP) ./$(SETUP) -configure $(CONFIGUREFLAGS) .PHONY: default build doc test all install uninstall reinstall clean distclean configure core-113.00.00/README.md000066400000000000000000000010511256461075500142330ustar00rootroot00000000000000Core is an industrial-strength alternative to the OCaml standard library. It was developed by Jane Street, which is the largest industrial user of OCaml. Core provides an overlay on the usual namespace, so the best way to use Core is to start your file with: ```ocaml open Core.Std ``` Please report bugs and feature requests on [GitHub](https://github.com/janestreet/core). For everything else you can contact us at . You can find all of Jane Street's open-source libraries on [GitHub](https://github.com/janestreet). core-113.00.00/THIRD-PARTY.txt000066400000000000000000000013601256461075500152670ustar00rootroot00000000000000The repository contains 3rd-party code in the following locations and under the following licenses: - type_conv, sexplib and bin_prot: based on Tywith, by Martin Sandin. License can be found in base/sexplib/LICENSE-Tywith.txt, base/type_conv/LICENSE-Tywith.txt, and base/bin_prot/LICENSE-Tywith.txt. - Core's implementation of union-find: based on an implementation by Henry Matthew Fluet, Suresh Jagannathan, and Stephen Weeks. License can be found in base/core/MLton-license. - Various Core libraries are based on INRIA's OCaml distribution. Relicensed under Apache 2.0, as permitted under the Caml License for Consortium members: http://caml.inria.fr/consortium/license.en.html See also the disclaimer INRIA-DISCLAIMER.txt. core-113.00.00/_oasis000066400000000000000000000255171256461075500141710ustar00rootroot00000000000000OASISFormat: 0.3 OCamlVersion: >= 4.00.1 FindlibVersion: >= 1.3.2 Name: core Version: 113.00.00 Synopsis: Jane Street Capital's standard library overlay Authors: Jane Street Group, LLC Copyrights: (C) 2008-2013 Jane Street Group LLC Maintainers: Jane Street Group, LLC License: Apache-2.0 LicenseFile: LICENSE.txt Homepage: https://github.com/janestreet/core Plugins: StdFiles (0.3), DevFiles (0.3), META (0.3) XStdFilesAUTHORS: false XStdFilesREADME: false BuildTools: ocamlbuild, camlp4o Description: The Core suite of libraries is an industrial strength alternative to OCaml's standard library that was developed by Jane Street, the largest industrial user of OCaml. Flag linux Description: Enable linux specific extensions Default$: flag(linux_possible) Flag "posix-timers" Description: Enable POSIX timers Default$: flag(posix_timers_possible) Flag "rt" Description: Linux RT Library Default$: flag(rt_possible) PreConfCommand: config/detect.sh PostConfCommand: config/discover.sh $ocamlc src/core_config.mlh src/core_config.h PreDistCleanCommand: $rm src/core_config.mlh src/core_config.h Library core Path: src FindlibName: core Pack: true Modules: Bigbuffer, Bigstring_marshal, Bigstring, Caml, Check_std, Command, Core_condition, Core_filename, Core_list, Core_mutex, Core_sys, Core_thread, Core_unix, Crc, Daemon, Date0, Date, Debug, Interval_intf, Interval, Iobuf_debug, Iobuf_intf, Iobuf, Iobuf_tests, Limiter, Limiter_unit_tests, Linux_ext, Lock_file, Mutex0, Nano_mutex, Ofday, Piecewise_linear_intf, Piecewise_linear, Process_env, Signal, Span, Squeue, Stable, Std, Syscall_result_intf, Syscall_result, Syslog, Thread_safe_queue_unit_tests, Time0, Time_internal, Time, Time_ns_benchmarks, Time_ns, Time_stamp_counter, Time_stamp_counter_benchmarks, Timing_wheel_float, Timing_wheel_float_unit_tests, Unix_error, User_and_group, Uuid, Weak_hashtbl, Zone, # Deprecated aliases kept for compatibility Array_permute, Avltree, Bag, Bigbuffer_internal, Bigsubstring, Binable, Binable0, Binary_packing, Blang, Bool, Bounded_int_table, Bucket, Byte_units, Commutative_group, Comparable, Comparable_intf, Comparator, Constrained_float, Container, Core_arg, Core_array, Core_bin_prot, Core_char, Core_field, Core_hashtbl, Core_hashtbl_intf, Core_int, Core_int32, Core_int63, Core_int64, Core_lazy, Core_map, Core_map_intf, Core_map_unit_tests, Core_nativeint, Core_printexc, Core_printf, Core_random, Core_set, Core_set_intf, Core_set_unit_tests, Core_sexp, Core_stack, Core_string, Day_of_week, Dequeue, Doubly_linked, Equal, Error, Exn, Flags, Flags_intf, Float, Float_intf, Float_robust_compare, Floatable, Fn, Force_once, Fqueue, Hash_heap, Hash_queue, Hash_set, Hash_set_intf, Hashable, Heap, Heap_block, Host_and_port, Identifiable, In_channel, Info, Int_conversions, Int_intf, Int_replace_polymorphic_compare, Int_set, Intable, Interfaces, Invariant, Make_substring, Memo, Monad, Month, Never_returns, No_polymorphic_compare, Nothing, Nothing0, Only_in_test, Option, Or_error, Ordered_collection_common, Ordering, Out_channel, Pid, Polymorphic_compare, Polymorphic_compare_intf, Pretty_printer, Ref, Result, Robustly_comparable, Set_once, Sexpable, Source_code_position, Source_code_position0, Stable_containers, Stable_internal, Stable_unit_test, Stable_unit_test_intf, Staged, Std_common, Std_internal, Std_kernel, String_id, Stringable, Substring, Substring_intf, T, Tuple, Type_equal, Union_find, Unique_id, Unique_id_intf, Unit, Univ, Univ_map, Unpack_buffer, Validate, Word_size CSources: bigstring_stubs.c, crc_stubs.c, includes.h, iobuf.h, iobuf_stubs.c, jane_common.h, linux_ext_stubs.c, nanosecond_stat.h, ocaml_utils.h, ocaml_utils_macros.h, ocaml_utils_stubs.c, recvmmsg.c, recvmmsg.h, signal_stubs.c, socketaddr.h, syslog_stubs.c, timespec.c, timespec.h, time_ns_stubs.c, time_stamp_counter_stubs.c, unix_stubs.c, unix_time_stubs.c, unix_utils.h, core_config.h BuildDepends: bigarray, bin_prot, bin_prot.syntax, comparelib.syntax, core_kernel, custom_printf, custom_printf.syntax, enumerate.syntax, fieldslib, fieldslib.syntax, herelib, herelib.syntax, pa_bench, pa_bench.syntax, pa_ounit, pa_ounit.syntax, pa_pipebang, pa_structural_sexp, pa_structural_sexp.syntax, pa_test, pa_test.syntax, sexplib, sexplib.syntax, sexplib_unix, typerep_lib, typerep_lib.syntax, unix, variantslib, variantslib.syntax, threads XMETARequires: bin_prot, core_kernel, custom_printf, variantslib, sexplib, sexplib_unix, enumerate, fieldslib, bigarray, pa_bench, pa_ounit, pa_structural_sexp, pa_test, unix, threads, typerep_lib XMETAExtraLines: archive(byte, toploop) += "core_top.cma" archive(native, toploop) += "core_top.cmxa" if flag(rt) CCLib: -lrt Library core_top Path: top FindlibName: top FindlibParent: core Modules: Core_install_printers XMETARequires: core XMETADescription: Toplevel printers for Core BuildDepends: core,compiler-libs Executable test_runner Path: test MainIs: test_runner.ml Build$: flag(tests) Custom: true CompiledObject: best Install: false BuildDepends: core,oUnit (>= 1.0.2) Test test_runner Run$: flag(tests) Command: $test_runner WorkingDirectory: test core-113.00.00/_tags000066400000000000000000000770511256461075500140110ustar00rootroot00000000000000<**/*.ml> : warn(-40) : pa_ounit_lib(core) <{src,test}/*.ml{,i}> : syntax_camlp4o "src/backtrace.ml" : mlh, package(camlp4.macro) "src/bigstring.ml" : mlh, package(camlp4.macro) "src/bigstring_marshal.ml" : mlh, package(camlp4.macro) "src/binary_packing.ml" : mlh, package(camlp4.macro) "src/command.ml" : mlh, package(camlp4.macro) "src/core_int63.ml" : mlh, package(camlp4.macro) "src/core_mutex.ml" : mlh, package(camlp4.macro) "src/core_unix.mli" : mlh, package(camlp4.macro) "src/core_unix.ml" : mlh, package(camlp4.macro) "src/linux_ext.ml" : mlh, package(camlp4.macro) "src/iobuf.ml" : mlh, package(camlp4.macro) "src/iobuf_tests.ml" : mlh, package(camlp4.macro) "src/std.ml" : mlh, package(camlp4.macro) "src/time_internal.ml" : mlh, package(camlp4.macro) "src/time_ns.ml" : mlh, package(camlp4.macro) "src/time_stamp_counter.ml" : mlh, package(camlp4.macro) "src/time_stamp_counter.mli" : mlh, package(camlp4.macro) # OASIS_START # DO NOT EDIT (digest: f0b6c2851d32b93c783469875d21d4e6) # Ignore VCS directories, you can use the same kind of rule outside # OASIS_START/STOP if you want to exclude directories that contains # useless stuff for the build process true: annot, bin_annot <**/.svn>: -traverse <**/.svn>: not_hygienic ".bzr": -traverse ".bzr": not_hygienic ".hg": -traverse ".hg": not_hygienic ".git": -traverse ".git": not_hygienic "_darcs": -traverse "_darcs": not_hygienic # Library core "src/core.cmxs": use_core "src/bigbuffer.cmx": for-pack(Core) "src/bigstring_marshal.cmx": for-pack(Core) "src/bigstring.cmx": for-pack(Core) "src/caml.cmx": for-pack(Core) "src/check_std.cmx": for-pack(Core) "src/command.cmx": for-pack(Core) "src/core_condition.cmx": for-pack(Core) "src/core_filename.cmx": for-pack(Core) "src/core_list.cmx": for-pack(Core) "src/core_mutex.cmx": for-pack(Core) "src/core_sys.cmx": for-pack(Core) "src/core_thread.cmx": for-pack(Core) "src/core_unix.cmx": for-pack(Core) "src/crc.cmx": for-pack(Core) "src/daemon.cmx": for-pack(Core) "src/date0.cmx": for-pack(Core) "src/date.cmx": for-pack(Core) "src/debug.cmx": for-pack(Core) "src/interval_intf.cmx": for-pack(Core) "src/interval.cmx": for-pack(Core) "src/iobuf_debug.cmx": for-pack(Core) "src/iobuf_intf.cmx": for-pack(Core) "src/iobuf.cmx": for-pack(Core) "src/iobuf_tests.cmx": for-pack(Core) "src/limiter.cmx": for-pack(Core) "src/limiter_unit_tests.cmx": for-pack(Core) "src/linux_ext.cmx": for-pack(Core) "src/lock_file.cmx": for-pack(Core) "src/mutex0.cmx": for-pack(Core) "src/nano_mutex.cmx": for-pack(Core) "src/ofday.cmx": for-pack(Core) "src/piecewise_linear_intf.cmx": for-pack(Core) "src/piecewise_linear.cmx": for-pack(Core) "src/process_env.cmx": for-pack(Core) "src/signal.cmx": for-pack(Core) "src/span.cmx": for-pack(Core) "src/squeue.cmx": for-pack(Core) "src/stable.cmx": for-pack(Core) "src/std.cmx": for-pack(Core) "src/syscall_result_intf.cmx": for-pack(Core) "src/syscall_result.cmx": for-pack(Core) "src/syslog.cmx": for-pack(Core) "src/thread_safe_queue_unit_tests.cmx": for-pack(Core) "src/time0.cmx": for-pack(Core) "src/time_internal.cmx": for-pack(Core) "src/time.cmx": for-pack(Core) "src/time_ns_benchmarks.cmx": for-pack(Core) "src/time_ns.cmx": for-pack(Core) "src/time_stamp_counter.cmx": for-pack(Core) "src/time_stamp_counter_benchmarks.cmx": for-pack(Core) "src/timing_wheel_float.cmx": for-pack(Core) "src/timing_wheel_float_unit_tests.cmx": for-pack(Core) "src/unix_error.cmx": for-pack(Core) "src/user_and_group.cmx": for-pack(Core) "src/uuid.cmx": for-pack(Core) "src/weak_hashtbl.cmx": for-pack(Core) "src/zone.cmx": for-pack(Core) "src/array_permute.cmx": for-pack(Core) "src/avltree.cmx": for-pack(Core) "src/bag.cmx": for-pack(Core) "src/bigbuffer_internal.cmx": for-pack(Core) "src/bigsubstring.cmx": for-pack(Core) "src/binable.cmx": for-pack(Core) "src/binable0.cmx": for-pack(Core) "src/binary_packing.cmx": for-pack(Core) "src/blang.cmx": for-pack(Core) "src/bool.cmx": for-pack(Core) "src/bounded_int_table.cmx": for-pack(Core) "src/bucket.cmx": for-pack(Core) "src/byte_units.cmx": for-pack(Core) "src/commutative_group.cmx": for-pack(Core) "src/comparable.cmx": for-pack(Core) "src/comparable_intf.cmx": for-pack(Core) "src/comparator.cmx": for-pack(Core) "src/constrained_float.cmx": for-pack(Core) "src/container.cmx": for-pack(Core) "src/core_arg.cmx": for-pack(Core) "src/core_array.cmx": for-pack(Core) "src/core_bin_prot.cmx": for-pack(Core) "src/core_char.cmx": for-pack(Core) "src/core_field.cmx": for-pack(Core) "src/core_hashtbl.cmx": for-pack(Core) "src/core_hashtbl_intf.cmx": for-pack(Core) "src/core_int.cmx": for-pack(Core) "src/core_int32.cmx": for-pack(Core) "src/core_int63.cmx": for-pack(Core) "src/core_int64.cmx": for-pack(Core) "src/core_lazy.cmx": for-pack(Core) "src/core_map.cmx": for-pack(Core) "src/core_map_intf.cmx": for-pack(Core) "src/core_map_unit_tests.cmx": for-pack(Core) "src/core_nativeint.cmx": for-pack(Core) "src/core_printexc.cmx": for-pack(Core) "src/core_printf.cmx": for-pack(Core) "src/core_random.cmx": for-pack(Core) "src/core_set.cmx": for-pack(Core) "src/core_set_intf.cmx": for-pack(Core) "src/core_set_unit_tests.cmx": for-pack(Core) "src/core_sexp.cmx": for-pack(Core) "src/core_stack.cmx": for-pack(Core) "src/core_string.cmx": for-pack(Core) "src/day_of_week.cmx": for-pack(Core) "src/dequeue.cmx": for-pack(Core) "src/doubly_linked.cmx": for-pack(Core) "src/equal.cmx": for-pack(Core) "src/error.cmx": for-pack(Core) "src/exn.cmx": for-pack(Core) "src/flags.cmx": for-pack(Core) "src/flags_intf.cmx": for-pack(Core) "src/float.cmx": for-pack(Core) "src/float_intf.cmx": for-pack(Core) "src/float_robust_compare.cmx": for-pack(Core) "src/floatable.cmx": for-pack(Core) "src/fn.cmx": for-pack(Core) "src/force_once.cmx": for-pack(Core) "src/fqueue.cmx": for-pack(Core) "src/hash_heap.cmx": for-pack(Core) "src/hash_queue.cmx": for-pack(Core) "src/hash_set.cmx": for-pack(Core) "src/hash_set_intf.cmx": for-pack(Core) "src/hashable.cmx": for-pack(Core) "src/heap.cmx": for-pack(Core) "src/heap_block.cmx": for-pack(Core) "src/host_and_port.cmx": for-pack(Core) "src/identifiable.cmx": for-pack(Core) "src/in_channel.cmx": for-pack(Core) "src/info.cmx": for-pack(Core) "src/int_conversions.cmx": for-pack(Core) "src/int_intf.cmx": for-pack(Core) "src/int_replace_polymorphic_compare.cmx": for-pack(Core) "src/int_set.cmx": for-pack(Core) "src/intable.cmx": for-pack(Core) "src/interfaces.cmx": for-pack(Core) "src/invariant.cmx": for-pack(Core) "src/make_substring.cmx": for-pack(Core) "src/memo.cmx": for-pack(Core) "src/monad.cmx": for-pack(Core) "src/month.cmx": for-pack(Core) "src/never_returns.cmx": for-pack(Core) "src/no_polymorphic_compare.cmx": for-pack(Core) "src/nothing.cmx": for-pack(Core) "src/nothing0.cmx": for-pack(Core) "src/only_in_test.cmx": for-pack(Core) "src/option.cmx": for-pack(Core) "src/or_error.cmx": for-pack(Core) "src/ordered_collection_common.cmx": for-pack(Core) "src/ordering.cmx": for-pack(Core) "src/out_channel.cmx": for-pack(Core) "src/pid.cmx": for-pack(Core) "src/polymorphic_compare.cmx": for-pack(Core) "src/polymorphic_compare_intf.cmx": for-pack(Core) "src/pretty_printer.cmx": for-pack(Core) "src/ref.cmx": for-pack(Core) "src/result.cmx": for-pack(Core) "src/robustly_comparable.cmx": for-pack(Core) "src/set_once.cmx": for-pack(Core) "src/sexpable.cmx": for-pack(Core) "src/source_code_position.cmx": for-pack(Core) "src/source_code_position0.cmx": for-pack(Core) "src/stable_containers.cmx": for-pack(Core) "src/stable_internal.cmx": for-pack(Core) "src/stable_unit_test.cmx": for-pack(Core) "src/stable_unit_test_intf.cmx": for-pack(Core) "src/staged.cmx": for-pack(Core) "src/std_common.cmx": for-pack(Core) "src/std_internal.cmx": for-pack(Core) "src/std_kernel.cmx": for-pack(Core) "src/string_id.cmx": for-pack(Core) "src/stringable.cmx": for-pack(Core) "src/substring.cmx": for-pack(Core) "src/substring_intf.cmx": for-pack(Core) "src/t.cmx": for-pack(Core) "src/tuple.cmx": for-pack(Core) "src/type_equal.cmx": for-pack(Core) "src/union_find.cmx": for-pack(Core) "src/unique_id.cmx": for-pack(Core) "src/unique_id_intf.cmx": for-pack(Core) "src/unit.cmx": for-pack(Core) "src/univ.cmx": for-pack(Core) "src/univ_map.cmx": for-pack(Core) "src/unpack_buffer.cmx": for-pack(Core) "src/validate.cmx": for-pack(Core) "src/word_size.cmx": for-pack(Core) : oasis_library_core_cclib "src/libcore_stubs.lib": oasis_library_core_cclib "src/dllcore_stubs.dll": oasis_library_core_cclib "src/libcore_stubs.a": oasis_library_core_cclib "src/dllcore_stubs.so": oasis_library_core_cclib : use_libcore_stubs : package(bigarray) : package(bin_prot) : package(bin_prot.syntax) : package(comparelib.syntax) : package(core_kernel) : package(custom_printf) : package(custom_printf.syntax) : package(enumerate.syntax) : package(fieldslib) : package(fieldslib.syntax) : package(herelib) : package(herelib.syntax) : package(pa_bench) : package(pa_bench.syntax) : package(pa_ounit) : package(pa_ounit.syntax) : package(pa_pipebang) : package(pa_structural_sexp) : package(pa_structural_sexp.syntax) : package(pa_test) : package(pa_test.syntax) : package(sexplib) : package(sexplib.syntax) : package(sexplib_unix) : package(threads) : package(typerep_lib) : package(typerep_lib.syntax) : package(unix) : package(variantslib) : package(variantslib.syntax) "src/bigstring_stubs.c": package(bigarray) "src/bigstring_stubs.c": package(bin_prot) "src/bigstring_stubs.c": package(bin_prot.syntax) "src/bigstring_stubs.c": package(comparelib.syntax) "src/bigstring_stubs.c": package(core_kernel) "src/bigstring_stubs.c": package(custom_printf) "src/bigstring_stubs.c": package(custom_printf.syntax) "src/bigstring_stubs.c": package(enumerate.syntax) "src/bigstring_stubs.c": package(fieldslib) "src/bigstring_stubs.c": package(fieldslib.syntax) "src/bigstring_stubs.c": package(herelib) "src/bigstring_stubs.c": package(herelib.syntax) "src/bigstring_stubs.c": package(pa_bench) "src/bigstring_stubs.c": package(pa_bench.syntax) "src/bigstring_stubs.c": package(pa_ounit) "src/bigstring_stubs.c": package(pa_ounit.syntax) "src/bigstring_stubs.c": package(pa_pipebang) "src/bigstring_stubs.c": package(pa_structural_sexp) "src/bigstring_stubs.c": package(pa_structural_sexp.syntax) "src/bigstring_stubs.c": package(pa_test) "src/bigstring_stubs.c": package(pa_test.syntax) "src/bigstring_stubs.c": package(sexplib) "src/bigstring_stubs.c": package(sexplib.syntax) "src/bigstring_stubs.c": package(sexplib_unix) "src/bigstring_stubs.c": package(threads) "src/bigstring_stubs.c": package(typerep_lib) "src/bigstring_stubs.c": package(typerep_lib.syntax) "src/bigstring_stubs.c": package(unix) "src/bigstring_stubs.c": package(variantslib) "src/bigstring_stubs.c": package(variantslib.syntax) "src/crc_stubs.c": package(bigarray) "src/crc_stubs.c": package(bin_prot) "src/crc_stubs.c": package(bin_prot.syntax) "src/crc_stubs.c": package(comparelib.syntax) "src/crc_stubs.c": package(core_kernel) "src/crc_stubs.c": package(custom_printf) "src/crc_stubs.c": package(custom_printf.syntax) "src/crc_stubs.c": package(enumerate.syntax) "src/crc_stubs.c": package(fieldslib) "src/crc_stubs.c": package(fieldslib.syntax) "src/crc_stubs.c": package(herelib) "src/crc_stubs.c": package(herelib.syntax) "src/crc_stubs.c": package(pa_bench) "src/crc_stubs.c": package(pa_bench.syntax) "src/crc_stubs.c": package(pa_ounit) "src/crc_stubs.c": package(pa_ounit.syntax) "src/crc_stubs.c": package(pa_pipebang) "src/crc_stubs.c": package(pa_structural_sexp) "src/crc_stubs.c": package(pa_structural_sexp.syntax) "src/crc_stubs.c": package(pa_test) "src/crc_stubs.c": package(pa_test.syntax) "src/crc_stubs.c": package(sexplib) "src/crc_stubs.c": package(sexplib.syntax) "src/crc_stubs.c": package(sexplib_unix) "src/crc_stubs.c": package(threads) "src/crc_stubs.c": package(typerep_lib) "src/crc_stubs.c": package(typerep_lib.syntax) "src/crc_stubs.c": package(unix) "src/crc_stubs.c": package(variantslib) "src/crc_stubs.c": package(variantslib.syntax) "src/iobuf_stubs.c": package(bigarray) "src/iobuf_stubs.c": package(bin_prot) "src/iobuf_stubs.c": package(bin_prot.syntax) "src/iobuf_stubs.c": package(comparelib.syntax) "src/iobuf_stubs.c": package(core_kernel) "src/iobuf_stubs.c": package(custom_printf) "src/iobuf_stubs.c": package(custom_printf.syntax) "src/iobuf_stubs.c": package(enumerate.syntax) "src/iobuf_stubs.c": package(fieldslib) "src/iobuf_stubs.c": package(fieldslib.syntax) "src/iobuf_stubs.c": package(herelib) "src/iobuf_stubs.c": package(herelib.syntax) "src/iobuf_stubs.c": package(pa_bench) "src/iobuf_stubs.c": package(pa_bench.syntax) "src/iobuf_stubs.c": package(pa_ounit) "src/iobuf_stubs.c": package(pa_ounit.syntax) "src/iobuf_stubs.c": package(pa_pipebang) "src/iobuf_stubs.c": package(pa_structural_sexp) "src/iobuf_stubs.c": package(pa_structural_sexp.syntax) "src/iobuf_stubs.c": package(pa_test) "src/iobuf_stubs.c": package(pa_test.syntax) "src/iobuf_stubs.c": package(sexplib) "src/iobuf_stubs.c": package(sexplib.syntax) "src/iobuf_stubs.c": package(sexplib_unix) "src/iobuf_stubs.c": package(threads) "src/iobuf_stubs.c": package(typerep_lib) "src/iobuf_stubs.c": package(typerep_lib.syntax) "src/iobuf_stubs.c": package(unix) "src/iobuf_stubs.c": package(variantslib) "src/iobuf_stubs.c": package(variantslib.syntax) "src/linux_ext_stubs.c": package(bigarray) "src/linux_ext_stubs.c": package(bin_prot) "src/linux_ext_stubs.c": package(bin_prot.syntax) "src/linux_ext_stubs.c": package(comparelib.syntax) "src/linux_ext_stubs.c": package(core_kernel) "src/linux_ext_stubs.c": package(custom_printf) "src/linux_ext_stubs.c": package(custom_printf.syntax) "src/linux_ext_stubs.c": package(enumerate.syntax) "src/linux_ext_stubs.c": package(fieldslib) "src/linux_ext_stubs.c": package(fieldslib.syntax) "src/linux_ext_stubs.c": package(herelib) "src/linux_ext_stubs.c": package(herelib.syntax) "src/linux_ext_stubs.c": package(pa_bench) "src/linux_ext_stubs.c": package(pa_bench.syntax) "src/linux_ext_stubs.c": package(pa_ounit) "src/linux_ext_stubs.c": package(pa_ounit.syntax) "src/linux_ext_stubs.c": package(pa_pipebang) "src/linux_ext_stubs.c": package(pa_structural_sexp) "src/linux_ext_stubs.c": package(pa_structural_sexp.syntax) "src/linux_ext_stubs.c": package(pa_test) "src/linux_ext_stubs.c": package(pa_test.syntax) "src/linux_ext_stubs.c": package(sexplib) "src/linux_ext_stubs.c": package(sexplib.syntax) "src/linux_ext_stubs.c": package(sexplib_unix) "src/linux_ext_stubs.c": package(threads) "src/linux_ext_stubs.c": package(typerep_lib) "src/linux_ext_stubs.c": package(typerep_lib.syntax) "src/linux_ext_stubs.c": package(unix) "src/linux_ext_stubs.c": package(variantslib) "src/linux_ext_stubs.c": package(variantslib.syntax) "src/ocaml_utils_stubs.c": package(bigarray) "src/ocaml_utils_stubs.c": package(bin_prot) "src/ocaml_utils_stubs.c": package(bin_prot.syntax) "src/ocaml_utils_stubs.c": package(comparelib.syntax) "src/ocaml_utils_stubs.c": package(core_kernel) "src/ocaml_utils_stubs.c": package(custom_printf) "src/ocaml_utils_stubs.c": package(custom_printf.syntax) "src/ocaml_utils_stubs.c": package(enumerate.syntax) "src/ocaml_utils_stubs.c": package(fieldslib) "src/ocaml_utils_stubs.c": package(fieldslib.syntax) "src/ocaml_utils_stubs.c": package(herelib) "src/ocaml_utils_stubs.c": package(herelib.syntax) "src/ocaml_utils_stubs.c": package(pa_bench) "src/ocaml_utils_stubs.c": package(pa_bench.syntax) "src/ocaml_utils_stubs.c": package(pa_ounit) "src/ocaml_utils_stubs.c": package(pa_ounit.syntax) "src/ocaml_utils_stubs.c": package(pa_pipebang) "src/ocaml_utils_stubs.c": package(pa_structural_sexp) "src/ocaml_utils_stubs.c": package(pa_structural_sexp.syntax) "src/ocaml_utils_stubs.c": package(pa_test) "src/ocaml_utils_stubs.c": package(pa_test.syntax) "src/ocaml_utils_stubs.c": package(sexplib) "src/ocaml_utils_stubs.c": package(sexplib.syntax) "src/ocaml_utils_stubs.c": package(sexplib_unix) "src/ocaml_utils_stubs.c": package(threads) "src/ocaml_utils_stubs.c": package(typerep_lib) "src/ocaml_utils_stubs.c": package(typerep_lib.syntax) "src/ocaml_utils_stubs.c": package(unix) "src/ocaml_utils_stubs.c": package(variantslib) "src/ocaml_utils_stubs.c": package(variantslib.syntax) "src/recvmmsg.c": package(bigarray) "src/recvmmsg.c": package(bin_prot) "src/recvmmsg.c": package(bin_prot.syntax) "src/recvmmsg.c": package(comparelib.syntax) "src/recvmmsg.c": package(core_kernel) "src/recvmmsg.c": package(custom_printf) "src/recvmmsg.c": package(custom_printf.syntax) "src/recvmmsg.c": package(enumerate.syntax) "src/recvmmsg.c": package(fieldslib) "src/recvmmsg.c": package(fieldslib.syntax) "src/recvmmsg.c": package(herelib) "src/recvmmsg.c": package(herelib.syntax) "src/recvmmsg.c": package(pa_bench) "src/recvmmsg.c": package(pa_bench.syntax) "src/recvmmsg.c": package(pa_ounit) "src/recvmmsg.c": package(pa_ounit.syntax) "src/recvmmsg.c": package(pa_pipebang) "src/recvmmsg.c": package(pa_structural_sexp) "src/recvmmsg.c": package(pa_structural_sexp.syntax) "src/recvmmsg.c": package(pa_test) "src/recvmmsg.c": package(pa_test.syntax) "src/recvmmsg.c": package(sexplib) "src/recvmmsg.c": package(sexplib.syntax) "src/recvmmsg.c": package(sexplib_unix) "src/recvmmsg.c": package(threads) "src/recvmmsg.c": package(typerep_lib) "src/recvmmsg.c": package(typerep_lib.syntax) "src/recvmmsg.c": package(unix) "src/recvmmsg.c": package(variantslib) "src/recvmmsg.c": package(variantslib.syntax) "src/signal_stubs.c": package(bigarray) "src/signal_stubs.c": package(bin_prot) "src/signal_stubs.c": package(bin_prot.syntax) "src/signal_stubs.c": package(comparelib.syntax) "src/signal_stubs.c": package(core_kernel) "src/signal_stubs.c": package(custom_printf) "src/signal_stubs.c": package(custom_printf.syntax) "src/signal_stubs.c": package(enumerate.syntax) "src/signal_stubs.c": package(fieldslib) "src/signal_stubs.c": package(fieldslib.syntax) "src/signal_stubs.c": package(herelib) "src/signal_stubs.c": package(herelib.syntax) "src/signal_stubs.c": package(pa_bench) "src/signal_stubs.c": package(pa_bench.syntax) "src/signal_stubs.c": package(pa_ounit) "src/signal_stubs.c": package(pa_ounit.syntax) "src/signal_stubs.c": package(pa_pipebang) "src/signal_stubs.c": package(pa_structural_sexp) "src/signal_stubs.c": package(pa_structural_sexp.syntax) "src/signal_stubs.c": package(pa_test) "src/signal_stubs.c": package(pa_test.syntax) "src/signal_stubs.c": package(sexplib) "src/signal_stubs.c": package(sexplib.syntax) "src/signal_stubs.c": package(sexplib_unix) "src/signal_stubs.c": package(threads) "src/signal_stubs.c": package(typerep_lib) "src/signal_stubs.c": package(typerep_lib.syntax) "src/signal_stubs.c": package(unix) "src/signal_stubs.c": package(variantslib) "src/signal_stubs.c": package(variantslib.syntax) "src/syslog_stubs.c": package(bigarray) "src/syslog_stubs.c": package(bin_prot) "src/syslog_stubs.c": package(bin_prot.syntax) "src/syslog_stubs.c": package(comparelib.syntax) "src/syslog_stubs.c": package(core_kernel) "src/syslog_stubs.c": package(custom_printf) "src/syslog_stubs.c": package(custom_printf.syntax) "src/syslog_stubs.c": package(enumerate.syntax) "src/syslog_stubs.c": package(fieldslib) "src/syslog_stubs.c": package(fieldslib.syntax) "src/syslog_stubs.c": package(herelib) "src/syslog_stubs.c": package(herelib.syntax) "src/syslog_stubs.c": package(pa_bench) "src/syslog_stubs.c": package(pa_bench.syntax) "src/syslog_stubs.c": package(pa_ounit) "src/syslog_stubs.c": package(pa_ounit.syntax) "src/syslog_stubs.c": package(pa_pipebang) "src/syslog_stubs.c": package(pa_structural_sexp) "src/syslog_stubs.c": package(pa_structural_sexp.syntax) "src/syslog_stubs.c": package(pa_test) "src/syslog_stubs.c": package(pa_test.syntax) "src/syslog_stubs.c": package(sexplib) "src/syslog_stubs.c": package(sexplib.syntax) "src/syslog_stubs.c": package(sexplib_unix) "src/syslog_stubs.c": package(threads) "src/syslog_stubs.c": package(typerep_lib) "src/syslog_stubs.c": package(typerep_lib.syntax) "src/syslog_stubs.c": package(unix) "src/syslog_stubs.c": package(variantslib) "src/syslog_stubs.c": package(variantslib.syntax) "src/timespec.c": package(bigarray) "src/timespec.c": package(bin_prot) "src/timespec.c": package(bin_prot.syntax) "src/timespec.c": package(comparelib.syntax) "src/timespec.c": package(core_kernel) "src/timespec.c": package(custom_printf) "src/timespec.c": package(custom_printf.syntax) "src/timespec.c": package(enumerate.syntax) "src/timespec.c": package(fieldslib) "src/timespec.c": package(fieldslib.syntax) "src/timespec.c": package(herelib) "src/timespec.c": package(herelib.syntax) "src/timespec.c": package(pa_bench) "src/timespec.c": package(pa_bench.syntax) "src/timespec.c": package(pa_ounit) "src/timespec.c": package(pa_ounit.syntax) "src/timespec.c": package(pa_pipebang) "src/timespec.c": package(pa_structural_sexp) "src/timespec.c": package(pa_structural_sexp.syntax) "src/timespec.c": package(pa_test) "src/timespec.c": package(pa_test.syntax) "src/timespec.c": package(sexplib) "src/timespec.c": package(sexplib.syntax) "src/timespec.c": package(sexplib_unix) "src/timespec.c": package(threads) "src/timespec.c": package(typerep_lib) "src/timespec.c": package(typerep_lib.syntax) "src/timespec.c": package(unix) "src/timespec.c": package(variantslib) "src/timespec.c": package(variantslib.syntax) "src/time_ns_stubs.c": package(bigarray) "src/time_ns_stubs.c": package(bin_prot) "src/time_ns_stubs.c": package(bin_prot.syntax) "src/time_ns_stubs.c": package(comparelib.syntax) "src/time_ns_stubs.c": package(core_kernel) "src/time_ns_stubs.c": package(custom_printf) "src/time_ns_stubs.c": package(custom_printf.syntax) "src/time_ns_stubs.c": package(enumerate.syntax) "src/time_ns_stubs.c": package(fieldslib) "src/time_ns_stubs.c": package(fieldslib.syntax) "src/time_ns_stubs.c": package(herelib) "src/time_ns_stubs.c": package(herelib.syntax) "src/time_ns_stubs.c": package(pa_bench) "src/time_ns_stubs.c": package(pa_bench.syntax) "src/time_ns_stubs.c": package(pa_ounit) "src/time_ns_stubs.c": package(pa_ounit.syntax) "src/time_ns_stubs.c": package(pa_pipebang) "src/time_ns_stubs.c": package(pa_structural_sexp) "src/time_ns_stubs.c": package(pa_structural_sexp.syntax) "src/time_ns_stubs.c": package(pa_test) "src/time_ns_stubs.c": package(pa_test.syntax) "src/time_ns_stubs.c": package(sexplib) "src/time_ns_stubs.c": package(sexplib.syntax) "src/time_ns_stubs.c": package(sexplib_unix) "src/time_ns_stubs.c": package(threads) "src/time_ns_stubs.c": package(typerep_lib) "src/time_ns_stubs.c": package(typerep_lib.syntax) "src/time_ns_stubs.c": package(unix) "src/time_ns_stubs.c": package(variantslib) "src/time_ns_stubs.c": package(variantslib.syntax) "src/time_stamp_counter_stubs.c": package(bigarray) "src/time_stamp_counter_stubs.c": package(bin_prot) "src/time_stamp_counter_stubs.c": package(bin_prot.syntax) "src/time_stamp_counter_stubs.c": package(comparelib.syntax) "src/time_stamp_counter_stubs.c": package(core_kernel) "src/time_stamp_counter_stubs.c": package(custom_printf) "src/time_stamp_counter_stubs.c": package(custom_printf.syntax) "src/time_stamp_counter_stubs.c": package(enumerate.syntax) "src/time_stamp_counter_stubs.c": package(fieldslib) "src/time_stamp_counter_stubs.c": package(fieldslib.syntax) "src/time_stamp_counter_stubs.c": package(herelib) "src/time_stamp_counter_stubs.c": package(herelib.syntax) "src/time_stamp_counter_stubs.c": package(pa_bench) "src/time_stamp_counter_stubs.c": package(pa_bench.syntax) "src/time_stamp_counter_stubs.c": package(pa_ounit) "src/time_stamp_counter_stubs.c": package(pa_ounit.syntax) "src/time_stamp_counter_stubs.c": package(pa_pipebang) "src/time_stamp_counter_stubs.c": package(pa_structural_sexp) "src/time_stamp_counter_stubs.c": package(pa_structural_sexp.syntax) "src/time_stamp_counter_stubs.c": package(pa_test) "src/time_stamp_counter_stubs.c": package(pa_test.syntax) "src/time_stamp_counter_stubs.c": package(sexplib) "src/time_stamp_counter_stubs.c": package(sexplib.syntax) "src/time_stamp_counter_stubs.c": package(sexplib_unix) "src/time_stamp_counter_stubs.c": package(threads) "src/time_stamp_counter_stubs.c": package(typerep_lib) "src/time_stamp_counter_stubs.c": package(typerep_lib.syntax) "src/time_stamp_counter_stubs.c": package(unix) "src/time_stamp_counter_stubs.c": package(variantslib) "src/time_stamp_counter_stubs.c": package(variantslib.syntax) "src/unix_stubs.c": package(bigarray) "src/unix_stubs.c": package(bin_prot) "src/unix_stubs.c": package(bin_prot.syntax) "src/unix_stubs.c": package(comparelib.syntax) "src/unix_stubs.c": package(core_kernel) "src/unix_stubs.c": package(custom_printf) "src/unix_stubs.c": package(custom_printf.syntax) "src/unix_stubs.c": package(enumerate.syntax) "src/unix_stubs.c": package(fieldslib) "src/unix_stubs.c": package(fieldslib.syntax) "src/unix_stubs.c": package(herelib) "src/unix_stubs.c": package(herelib.syntax) "src/unix_stubs.c": package(pa_bench) "src/unix_stubs.c": package(pa_bench.syntax) "src/unix_stubs.c": package(pa_ounit) "src/unix_stubs.c": package(pa_ounit.syntax) "src/unix_stubs.c": package(pa_pipebang) "src/unix_stubs.c": package(pa_structural_sexp) "src/unix_stubs.c": package(pa_structural_sexp.syntax) "src/unix_stubs.c": package(pa_test) "src/unix_stubs.c": package(pa_test.syntax) "src/unix_stubs.c": package(sexplib) "src/unix_stubs.c": package(sexplib.syntax) "src/unix_stubs.c": package(sexplib_unix) "src/unix_stubs.c": package(threads) "src/unix_stubs.c": package(typerep_lib) "src/unix_stubs.c": package(typerep_lib.syntax) "src/unix_stubs.c": package(unix) "src/unix_stubs.c": package(variantslib) "src/unix_stubs.c": package(variantslib.syntax) "src/unix_time_stubs.c": package(bigarray) "src/unix_time_stubs.c": package(bin_prot) "src/unix_time_stubs.c": package(bin_prot.syntax) "src/unix_time_stubs.c": package(comparelib.syntax) "src/unix_time_stubs.c": package(core_kernel) "src/unix_time_stubs.c": package(custom_printf) "src/unix_time_stubs.c": package(custom_printf.syntax) "src/unix_time_stubs.c": package(enumerate.syntax) "src/unix_time_stubs.c": package(fieldslib) "src/unix_time_stubs.c": package(fieldslib.syntax) "src/unix_time_stubs.c": package(herelib) "src/unix_time_stubs.c": package(herelib.syntax) "src/unix_time_stubs.c": package(pa_bench) "src/unix_time_stubs.c": package(pa_bench.syntax) "src/unix_time_stubs.c": package(pa_ounit) "src/unix_time_stubs.c": package(pa_ounit.syntax) "src/unix_time_stubs.c": package(pa_pipebang) "src/unix_time_stubs.c": package(pa_structural_sexp) "src/unix_time_stubs.c": package(pa_structural_sexp.syntax) "src/unix_time_stubs.c": package(pa_test) "src/unix_time_stubs.c": package(pa_test.syntax) "src/unix_time_stubs.c": package(sexplib) "src/unix_time_stubs.c": package(sexplib.syntax) "src/unix_time_stubs.c": package(sexplib_unix) "src/unix_time_stubs.c": package(threads) "src/unix_time_stubs.c": package(typerep_lib) "src/unix_time_stubs.c": package(typerep_lib.syntax) "src/unix_time_stubs.c": package(unix) "src/unix_time_stubs.c": package(variantslib) "src/unix_time_stubs.c": package(variantslib.syntax) # Library core_top "top/core_top.cmxs": use_core_top : package(bigarray) : package(bin_prot) : package(bin_prot.syntax) : package(comparelib.syntax) : package(compiler-libs) : package(core_kernel) : package(custom_printf) : package(custom_printf.syntax) : package(enumerate.syntax) : package(fieldslib) : package(fieldslib.syntax) : package(herelib) : package(herelib.syntax) : package(pa_bench) : package(pa_bench.syntax) : package(pa_ounit) : package(pa_ounit.syntax) : package(pa_pipebang) : package(pa_structural_sexp) : package(pa_structural_sexp.syntax) : package(pa_test) : package(pa_test.syntax) : package(sexplib) : package(sexplib.syntax) : package(sexplib_unix) : package(threads) : package(typerep_lib) : package(typerep_lib.syntax) : package(unix) : package(variantslib) : package(variantslib.syntax) : use_core # Executable test_runner : package(bigarray) : package(bin_prot) : package(bin_prot.syntax) : package(comparelib.syntax) : package(core_kernel) : package(custom_printf) : package(custom_printf.syntax) : package(enumerate.syntax) : package(fieldslib) : package(fieldslib.syntax) : package(herelib) : package(herelib.syntax) : package(oUnit) : package(pa_bench) : package(pa_bench.syntax) : package(pa_ounit) : package(pa_ounit.syntax) : package(pa_pipebang) : package(pa_structural_sexp) : package(pa_structural_sexp.syntax) : package(pa_test) : package(pa_test.syntax) : package(sexplib) : package(sexplib.syntax) : package(sexplib_unix) : package(threads) : package(typerep_lib) : package(typerep_lib.syntax) : package(unix) : package(variantslib) : package(variantslib.syntax) : use_core : package(bigarray) : package(bin_prot) : package(bin_prot.syntax) : package(comparelib.syntax) : package(core_kernel) : package(custom_printf) : package(custom_printf.syntax) : package(enumerate.syntax) : package(fieldslib) : package(fieldslib.syntax) : package(herelib) : package(herelib.syntax) : package(oUnit) : package(pa_bench) : package(pa_bench.syntax) : package(pa_ounit) : package(pa_ounit.syntax) : package(pa_pipebang) : package(pa_structural_sexp) : package(pa_structural_sexp.syntax) : package(pa_test) : package(pa_test.syntax) : package(sexplib) : package(sexplib.syntax) : package(sexplib_unix) : package(threads) : package(typerep_lib) : package(typerep_lib.syntax) : package(unix) : package(variantslib) : package(variantslib.syntax) : use_core : custom # OASIS_STOP core-113.00.00/bench/000077500000000000000000000000001256461075500140365ustar00rootroot00000000000000core-113.00.00/bench/array_heap.ml000066400000000000000000000204041256461075500165030ustar00rootroot00000000000000open Core.Std open Core_bench.Std (** A faster alternative implementation of heap. *) module Array_heap = struct type 'a t = { lt : 'a -> 'a -> bool; fa : bool; mutable a : 'a array; mutable l : int; } let create ~lt size init = let a = Array.create ~len:size init in let fa = Obj.tag (Obj.repr a) = Obj.double_array_tag in { a; fa; l = 0; lt } let swap t i j = let a : int array = Obj.magic t.a in let e = Array.unsafe_get a i in Array.unsafe_set a i (Array.unsafe_get a j); Array.unsafe_set a j e let down_heap t = let rec loop t i l = let ir = (i + 1) lsl 1 in let il = ir - 1 in let a : int array = Obj.magic t.a in if ir < l then begin let e : 'a = Obj.magic (Array.unsafe_get a i ) in let el : 'a = Obj.magic (Array.unsafe_get a il) in let er : 'a = Obj.magic (Array.unsafe_get a ir) in let lt = t.lt in if lt el er then begin if lt el e then begin swap t i il; loop t il l end end else if lt er e then begin swap t i ir; loop t ir l end end else if il < t.l then begin let e : 'a = Obj.magic (Array.unsafe_get a i ) in let el : 'a = Obj.magic (Array.unsafe_get a il) in if t.lt el e then swap t i il end in let rec loop_fa t i l = let ir = (i + 1) lsl 1 in let il = ir - 1 in let a : float array = Obj.magic t.a in if ir < l then begin let e : 'a = Obj.magic (Array.unsafe_get a i ) in let el : 'a = Obj.magic (Array.unsafe_get a il) in let er : 'a = Obj.magic (Array.unsafe_get a ir) in let lt = t.lt in if lt el er then begin if lt el e then begin swap t i il; loop_fa t il l end end else if lt er e then begin swap t i ir; loop_fa t ir l end end else if il < t.l then begin let e : 'a = Obj.magic (Array.unsafe_get a i ) in let el : 'a = Obj.magic (Array.unsafe_get a il) in if t.lt el e then swap t i il end in if t.fa then loop_fa t 0 t.l else loop t 0 t.l let up_heap t = let rec loop t i = let i' = (i - 1) lsr 1 in let a : int array = Obj.magic t.a in let e : 'a = Obj.magic (Array.unsafe_get a i) in let e' : 'a = Obj.magic (Array.unsafe_get a i') in if t.lt e e' then begin swap t i i'; if i' > 0 then loop t i' end in let rec loop_fa t i = let i' = (i - 1) lsr 1 in let a : float array = Obj.magic t.a in let e : 'a = Obj.magic (Array.unsafe_get a i) in let e' : 'a = Obj.magic (Array.unsafe_get a i') in if t.lt e e' then begin swap t i i'; if i' > 0 then loop_fa t i' end in let l = t.l - 1 in if l > 0 then begin if t.fa then loop_fa t l else loop t l end let add t x = let l = t.l in let l' = l + 1 in if l' > Array.length t.a then failwith "Heap full"; Array.unsafe_set t.a l x; t.l <- l'; up_heap t let pop_exn t = let l = t.l in if l = 0 then failwith "Heap empty"; let a = t.a in let x = Array.unsafe_get a 0 in let l = l - 1 in Array.unsafe_set a 0 (Array.unsafe_get a l); t.l <- l; down_heap t; x let top_exn t = let l = t.l in if l = 0 then failwith "Heap empty"; Array.unsafe_get t.a 0 let is_empty t = t.l = 0 end module Heap = Array_heap module Data = struct type t = { name : string; t : int array; l : int; mutable pos : int; } let range name high = let l = (1024 * 1024) - 1 in let t = Array.create ~len:(l + 1) 0 in for i = 0 to l do t.(i) <- Random.int high; done; { name; t; l; pos = 0 } ;; let small_range = range "small range" 10 let medium_range = range "medium range" 100 let large_range = range "large range" 1_000_000 let ascending = let l = (1024 * 1024) - 1 in let t = Array.create ~len:(l + 1) 0 in for i = 0 to Array.length t - 1 do t.(i) <- i; done; { name = "ascending"; t; l; pos = 0 } ;; let next t = let pos = t.pos in let n = Array.unsafe_get t.t pos in t.pos <- (pos + 1) land t.l; n ;; let name t = t.name end let add_remove_from_existing_heap data initial_size = let h = Heap.create ~lt:(fun (x : int) (x' : int) -> x < x') (initial_size + 1) 0 in for _i = 1 to initial_size do Heap.add h (Data.next data); done; Bench.Test.create ~name:(sprintf "add/remove from heap of size %i (%s)" initial_size (Data.name data)) (fun () -> Heap.add h (Data.next data); ignore (Heap.pop_exn h)) ;; let heap_sort data size = let l = let rec loop acc n = if n = 0 then acc else loop (Data.next data :: acc) (n - 1) in loop [] size in Bench.Test.create ~name:(sprintf "sort list of length %i (%s)" size (Data.name data)) (fun () -> let h = Heap.create ~lt:(fun (x : int) (x' : int) -> x < x') size 0 in List.iter l ~f:(fun i -> Heap.add h i); try let rec loop () = ignore (Heap.pop_exn h); loop () in loop () with | _ -> assert (Heap.is_empty h)) ;; let () = Bench.bench [ add_remove_from_existing_heap Data.small_range 0; add_remove_from_existing_heap Data.small_range 10; add_remove_from_existing_heap Data.small_range 1_000; add_remove_from_existing_heap Data.small_range 100_000; add_remove_from_existing_heap Data.small_range 1_000_000; add_remove_from_existing_heap Data.medium_range 0; add_remove_from_existing_heap Data.medium_range 10; add_remove_from_existing_heap Data.medium_range 1_000; add_remove_from_existing_heap Data.medium_range 100_000; add_remove_from_existing_heap Data.medium_range 1_000_000; add_remove_from_existing_heap Data.large_range 0; add_remove_from_existing_heap Data.large_range 10; add_remove_from_existing_heap Data.large_range 1_000; add_remove_from_existing_heap Data.large_range 100_000; add_remove_from_existing_heap Data.large_range 1_000_000; add_remove_from_existing_heap Data.ascending 0; add_remove_from_existing_heap Data.ascending 10; add_remove_from_existing_heap Data.ascending 1_000; add_remove_from_existing_heap Data.ascending 100_000; add_remove_from_existing_heap Data.ascending 1_000_000; heap_sort Data.small_range 10; heap_sort Data.small_range 1_000; heap_sort Data.small_range 10_000; heap_sort Data.small_range 1_000_000; heap_sort Data.medium_range 10; heap_sort Data.medium_range 1_000; heap_sort Data.medium_range 10_000; heap_sort Data.medium_range 1_000_000; heap_sort Data.large_range 10; heap_sort Data.large_range 1_000; heap_sort Data.large_range 10_000; heap_sort Data.large_range 1_000_000; heap_sort Data.ascending 10; heap_sort Data.ascending 1_000; heap_sort Data.ascending 10_000; heap_sort Data.ascending 1_000_000; ] (*let () = let n = Int.of_string Sys.argv.(1) in let r = Array.init n ~f:(fun _ -> Random.int n) in let ah = Array_heap.create ~lt:(fun (x : int ref) (y : int ref) -> !x < !y) n (ref 0) in for i = 0 to n - 1 do Array_heap.add ah (ref r.(i)) done; let array_heap_test = Bench.Test.create ~name:"Array_heap" (fun () -> let r = !(ref r) in let ah = !(ref ah) in let last = ref 0 in for i = 0 to Array.length r - 1 do let top = Array_heap.pop_exn ah in assert (!top >= !last); last := !top; top := !top + Array.unsafe_get r i; Array_heap.add ah top done) in let h = Heap.create ~cmp:(fun x y -> Int.compare !x !y) () in for i = 0 to Array.length r - 1 do Heap.add h (ref r.(i)); done; let heap_test = Bench.Test.create ~name:"Heap" (fun () -> let r = !(ref r) in let h = !(ref h) in for i = 0 to Array.length r - 1 do let top = Heap.pop_exn h in top := !top + Array.unsafe_get r i; Heap.add h top done) in Bench.bench ~run_config:(Bench.Run_config.create ~time_quota:(Time.Span.of_sec 1.) ()) [array_heap_test; heap_test]*) core-113.00.00/bench/array_iter.ml000066400000000000000000000007731256461075500165400ustar00rootroot00000000000000open Core.Std module Bench = Core_extended.Deprecated_bench let () = let a = Array.init 1000 ~f:ident in let test_array_iter = Bench.Test.create ~name:"array_iter" (fun () -> Array.iter a ~f:(fun i -> if i > 2000 then assert false)) in let test_array_for = Bench.Test.create ~name:"array_for" (fun () -> let length = (Array.length a) - 1 in for i = 0 to length do if i > 2000 then assert false done) in Bench.bench [test_array_iter; test_array_for] core-113.00.00/bench/array_sort.ml000066400000000000000000000231511256461075500165570ustar00rootroot00000000000000(** Demonstrates how [Obj.magic] can be used to speed up sorting. *) module Array = StdLabels.Array module List = Core_kernel.Core_list type 'a t = 'a array module Sort = struct let swap arr i j = let arr : int array = Obj.magic arr in let tmp = Array.unsafe_get arr i in Array.unsafe_set arr i (Array.unsafe_get arr j); Array.unsafe_set arr j tmp ;; module type Sort = sig val sort : 'a t -> cmp:('a -> 'a -> int) -> left:int (* leftmost index of sub-array to sort *) -> right:int (* rightmost index of sub-array to sort *) -> unit end (* http://en.wikipedia.org/wiki/Insertion_sort *) module Insertion_sort : Sort = struct let sort arr ~cmp ~left ~right = let arr : int array = Obj.magic arr in let insert pos v = (* loop invariants: 1. the subarray arr[left .. i-1] is sorted 2. the subarray arr[i+1 .. pos] is sorted and contains only elements > v 3. arr[i] may be thought of as containing v *) let rec loop i = let i_next = i - 1 in if i_next >= left && cmp (Obj.magic (Array.unsafe_get arr i_next)) v > 0 then begin Array.unsafe_set arr i (Array.unsafe_get arr i_next); loop i_next end else i in let final_pos = loop pos in Array.unsafe_set arr final_pos (Obj.magic v) in (* loop invariant: arr is sorted from left to i-1, inclusive *) for i = left + 1 to right do insert i (Obj.magic (Array.unsafe_get arr i)) done ;; end (* http://en.wikipedia.org/wiki/Heapsort *) module Heap_sort : Sort = struct (* loop invariant: root's children are both either roots of max-heaps or > right *) let rec heapify arr ~(cmp:'a -> 'a -> int) root ~left ~right = let arr : int array = Obj.magic arr in let relative_root = root - left in let left_child = (2 * relative_root) + left + 1 in let right_child = (2 * relative_root) + left + 2 in let largest = if left_child <= right && cmp (Obj.magic (Array.unsafe_get arr left_child)) (Obj.magic (Array.unsafe_get arr root)) > 0 then left_child else root in let largest = if right_child <= right && cmp (Obj.magic (Array.unsafe_get arr right_child)) (Obj.magic (Array.unsafe_get arr largest)) > 0 then right_child else largest in if largest <> root then begin swap arr root largest; heapify arr ~cmp largest ~left ~right end; ;; let build_heap arr ~cmp ~left ~right = let arr : int array = Obj.magic arr in (* Elements in the second half of the array are already heaps of size 1. We move through the first half of the array from back to front examining the element at hand, and the left and right children, fixing the heap property as we go. *) for i = (left + right) / 2 downto left do heapify arr ~cmp i ~left ~right; done; ;; let sort arr ~cmp ~left ~right = let arr : int array = Obj.magic arr in build_heap arr ~cmp ~left ~right; (* loop invariants: 1. the subarray arr[left ... i] is a max-heap H 2. the subarray arr[i+1 ... right] is sorted (call it S) 3. every element of H is less than every element of S *) for i = right downto left + 1 do swap arr left i; heapify arr ~cmp left ~left ~right:(i - 1); done; ;; end (* http://en.wikipedia.org/wiki/Introsort *) module Intro_sort : Sort = struct let five_element_sort arr ~cmp m1 m2 m3 m4 m5 = let arr : int array = Obj.magic arr in let compare_and_swap i j = let x = Obj.magic (Array.unsafe_get arr i) in let y = Obj.magic (Array.unsafe_get arr j) in if cmp x y > 0 then swap arr i j in (* optimal 5-element sorting network *) compare_and_swap m1 m2; (* 1--o-----o-----o--------------1 *) compare_and_swap m4 m5; (* | | | *) compare_and_swap m1 m3; (* 2--o-----|--o--|-----o--o-----2 *) compare_and_swap m2 m3; (* | | | | | *) compare_and_swap m1 m4; (* 3--------o--o--|--o--|--o-----3 *) compare_and_swap m3 m4; (* | | | *) compare_and_swap m2 m5; (* 4-----o--------o--o--|-----o--4 *) compare_and_swap m2 m3; (* | | | *) compare_and_swap m4 m5; (* 5-----o--------------o-----o--5 *) ;; (* choose pivots for the array by sorting 5 elements and examining the center three elements. The goal is to choose two pivots that will either: - break the range up into 3 even partitions or - eliminate a commonly appearing element by sorting it into the center partition by itself To this end we look at the center 3 elements of the 5 and return pairs of equal elements or the widest range *) let choose_pivots arr ~cmp ~left ~right = let sixth = (right - left) / 6 in let m1 = left + sixth in let m2 = m1 + sixth in let m3 = m2 + sixth in let m4 = m3 + sixth in let m5 = m4 + sixth in five_element_sort arr ~cmp m1 m2 m3 m4 m5; let m2_val = Array.unsafe_get arr m2 in let m3_val = Array.unsafe_get arr m3 in let m4_val = Array.unsafe_get arr m4 in if cmp m2_val m3_val = 0 then (m2_val, m3_val, true) else if cmp m3_val m4_val = 0 then (m3_val, m4_val, true) else (m2_val, m4_val, false) ;; let dual_pivot_partition arr ~cmp ~left ~right = let pivot1, pivot2, pivots_equal = choose_pivots arr ~cmp ~left ~right in let arr : int array = Obj.magic arr in (* loop invariants: 1. left <= l < r <= right 2. l <= p <= r 3. l <= x < p implies arr[x] >= pivot1 and arr[x] <= pivot2 4. left <= x < l implies arr[x] < pivot1 5. r < x <= right implies arr[x] > pivot2 *) let rec loop l p r = let pv = Obj.magic (Array.unsafe_get arr p) in if cmp pv pivot1 < 0 then begin swap arr p l; cont (l + 1) (p + 1) r end else if cmp pv pivot2 > 0 then begin (* loop invariants: same as those of the outer loop *) let rec scan_backwards r = if r > p && cmp (Obj.magic (Array.unsafe_get arr r)) pivot2 > 0 then scan_backwards (r - 1) else r in let r = scan_backwards r in swap arr r p; cont l p (r - 1) end else cont l (p + 1) r and cont l p r = if p > r then (l, r) else loop l p r in let (l, r) = cont left left right in (l, r, pivots_equal) ;; let rec intro_sort arr ~max_depth ~cmp ~left ~right = let len = right - left + 1 in (* This takes care of some edge cases, such as left > right or very short arrays, since Insertion_sort.sort handles these cases properly. Thus we don't need to make sure that left and right are valid in recursive calls. *) if len <= 32 then begin Insertion_sort.sort arr ~cmp ~left ~right end else if max_depth < 0 then begin Heap_sort.sort arr ~cmp ~left ~right; end else begin let max_depth = max_depth - 1 in let (l, r, middle_sorted) = dual_pivot_partition arr ~cmp ~left ~right in intro_sort arr ~max_depth ~cmp ~left ~right:(l - 1); if not middle_sorted then intro_sort arr ~max_depth ~cmp ~left:l ~right:r; intro_sort arr ~max_depth ~cmp ~left:(r + 1) ~right; end ;; let log10_of_3 = log10 3. let log3 x = log10 x /. log10_of_3 let sort arr ~cmp ~left ~right = let len = right - left + 1 in let heap_sort_switch_depth = (* with perfect 3-way partitioning, this is the recursion depth *) int_of_float (log3 (float_of_int len)) in intro_sort arr ~max_depth:heap_sort_switch_depth ~cmp ~left ~right; ;; end end let sort ?pos ?len arr ~cmp = let pos, len = Core_kernel.Ordered_collection_common.get_pos_len_exn ?pos ?len ~length:(Array.length arr) in Sort.Intro_sort.sort arr ~cmp ~left:pos ~right:(pos + len - 1) let () = let n = int_of_string Sys.argv.(1) in let iter = int_of_string Sys.argv.(2) in let r = Array.init n ~f:(fun _ -> Random.int n) in let a = Array.make n 0 in let start = Unix.gettimeofday () in let cmp (x : int) (x' : int) = compare x x' in for _i = 0 to iter do Array.blit ~src:r ~src_pos:0 ~dst:a ~dst_pos:0 ~len:n; sort a ~cmp done; Printf.printf "%f\n" (Unix.gettimeofday () -. start); for i = 0 to n - 2 do assert (a.(i) <= a.(i + 1)) done; let start = Unix.gettimeofday () in for _i = 0 to iter do Array.blit ~src:r ~src_pos:0 ~dst:a ~dst_pos:0 ~len:n; Core.Std.Array.sort a ~cmp done; Printf.printf "%f\n" (Unix.gettimeofday () -. start); let r = Array.init n ~f:(fun _ -> ref (Random.int n)) in let a = Array.make n (ref 0) in let start = Unix.gettimeofday () in let cmp (x : int ref) (x' : int ref) = compare !x !x' in for _i = 0 to iter do Array.blit ~src:r ~src_pos:0 ~dst:a ~dst_pos:0 ~len:n; sort a ~cmp done; Printf.printf "%f\n" (Unix.gettimeofday () -. start); for i = 0 to n - 2 do assert (!(a.(i)) <= !(a.(i + 1))) done; let start = Unix.gettimeofday () in for _i = 0 to iter do Array.blit ~src:r ~src_pos:0 ~dst:a ~dst_pos:0 ~len:n; Core.Std.Array.sort a ~cmp done; Printf.printf "%f\n" (Unix.gettimeofday () -. start); core-113.00.00/bench/bench_hashtbl.ml000066400000000000000000000041431256461075500171560ustar00rootroot00000000000000open Core.Std module Bench = Core_extended.Deprecated_bench module Test = Bench.Test module My_hashtbl = struct type ('k, 'v) t = { hash : ('k -> int) ; array : 'v option Array.t } let create ~size ~hash = let hash k = hash k mod size in { hash ; array = Array.create ~len:size None } let replace t ~key ~data = t.array.(t.hash key) <- Some data let find t key = t.array.(t.hash key) end module My_hashable = struct module Make(M:Hashtbl.Key) = struct module Table = struct include My_hashtbl let create ?(size=128) () = create ~size ~hash:M.hash end end end module Hashtbl_ = My_hashtbl module Hashable_ = My_hashable let gen_test_int_replace_and_find n tbl = let replace () = for i = 0 to n - 1 do Hashtbl.set tbl ~key:i ~data:i done in let find () = for i = 0 to n - 1 do let (_ : int option) = Hashtbl.find tbl i in () done in replace, find let () = let n = 1_000_000 in let int_tbl_replace1, int_tbl_find1 = let module I = Hashable.Make(struct include Int let hash x = Caml.Hashtbl.hash x end) in gen_test_int_replace_and_find n (I.Table.create ~size:(2*n) ()) in let int_tbl_replace2, int_tbl_find2 = let module I = Hashable.Make(struct include Int let hash x = Core.Std.Hashtbl_intf.Hashable.hash x end) in gen_test_int_replace_and_find n (I.Table.create ~size:(2*n) ()) in let caml_hashtbl_hash () = for i = 0 to n - 1 do let (_ : int) = Caml.Hashtbl.hash i in () done in let jst_hashtbl_hash () = for i = 0 to n - 1 do let (_ : int) = Core.Std.Hashtbl_intf.Hashable.hash i in () done in Bench.bench [ Test.create ~name:"Int-replace1" int_tbl_replace1 ; Test.create ~name:"Int-replace2" int_tbl_replace2 ; Test.create ~name:"Int-find1" int_tbl_find1 ; Test.create ~name:"Int-find2" int_tbl_find2 ; Test.create ~name:"Caml-hashtbl-hash" caml_hashtbl_hash ; Test.create ~name:"Jst-hashtbl-hash" jst_hashtbl_hash ] core-113.00.00/bench/bench_heap.ml000066400000000000000000000057201256461075500164500ustar00rootroot00000000000000open Core.Std open Core_bench.Std module Data = struct type t = { name : string ; mutable index : int ; data : int array } let range name high = let data = Array.init 1_000_000 ~f:(fun _ -> Random.int high) in { name; index = 0; data } ;; let small_range = range "small range" 10 let medium_range = range "medium range" 100 let large_range = range "large range" 1_000_000 let ascending = let len = 1_000_000 in let data = Array.init len ~f:(fun i -> len - i) in { name = "ascending"; index = len - 1; data } ;; let next t = let n = t.data.(t.index) in t.index <- t.index - 1; if t.index < 0 then t.index <- Array.length t.data - 1; n ;; let name t = t.name let reset t = t.index <- Array.length t.data - 1 end let add_remove_from_existing_heap data initial_size = let h = Heap.create ~cmp:Int.compare () in for _i = 1 to initial_size do Heap.add h (Data.next data); done; Bench.Test.create ~name:(sprintf "add/remove from heap of size %i (%s)" initial_size (Data.name data)) (fun () -> Heap.add h (Data.next data); ignore (Heap.pop_exn h)) ;; let heap_sort data size = Bench.Test.create ~name:(sprintf "sort list of length %i (%s)" size (Data.name data)) (fun () -> Data.reset data; let h = Heap.create ~cmp:Int.compare () in for _i = 1 to size do Heap.add h (Data.next data); done; for _i = 1 to size do ignore (Heap.pop_exn h); done; assert (Heap.is_empty h)) ;; let () = Command.run (Bench.make_command [ add_remove_from_existing_heap Data.small_range 0; add_remove_from_existing_heap Data.small_range 10; add_remove_from_existing_heap Data.small_range 1_000; add_remove_from_existing_heap Data.small_range 100_000; add_remove_from_existing_heap Data.medium_range 0; add_remove_from_existing_heap Data.medium_range 10; add_remove_from_existing_heap Data.medium_range 1_000; add_remove_from_existing_heap Data.medium_range 100_000; add_remove_from_existing_heap Data.large_range 0; add_remove_from_existing_heap Data.large_range 10; add_remove_from_existing_heap Data.large_range 1_000; add_remove_from_existing_heap Data.large_range 100_000; add_remove_from_existing_heap Data.ascending 0; add_remove_from_existing_heap Data.ascending 10; add_remove_from_existing_heap Data.ascending 1_000; add_remove_from_existing_heap Data.ascending 100_000; heap_sort Data.small_range 10; heap_sort Data.small_range 1_000; heap_sort Data.small_range 100_000; heap_sort Data.medium_range 10; heap_sort Data.medium_range 1_000; heap_sort Data.medium_range 100_000; heap_sort Data.large_range 10; heap_sort Data.large_range 1_000; heap_sort Data.large_range 100_000; heap_sort Data.ascending 10; heap_sort Data.ascending 1_000; heap_sort Data.ascending 100_000; ]) ;; core-113.00.00/bench/bench_map.ml000066400000000000000000000075321256461075500163130ustar00rootroot00000000000000open Core.Std module Bench = Core_bench.Std.Bench module Test = Bench.Test let size = 10_000 let alist = List.init size ~f:(fun i -> (i, i)) let of_alist_exn () = ignore ((Int.Map.of_alist_exn alist) : int Int.Map.t) let of_sorted_array () = let sorted_array = Array.init size ~f:(fun i -> (i, i)) in ignore (Int.Map.of_sorted_array sorted_array) let map = Int.Map.of_alist_exn alist let iter () = Map.iter map ~f:(fun ~key:_ ~data:_ -> ()) let iter2 () = Map.iter2 map map ~f:(fun ~key:_ ~data:_ -> ()) let iter2_naive () = let iter2 a b ~f = Map.iter a ~f:(fun ~key ~data:_ -> match Map.find b key with | None -> f `Left | Some _ -> f `Both ) in iter2 map map ~f:ignore let add = assert(not (Int.Map.mem map size)); fun () -> ignore (Map.add map ~key:size ~data:size) ;; let remove = let deep_key = fst (Map.min_elt_exn map) in fun () -> ignore (Map.remove map deep_key) ;; let old_map_merge t1 t2 ~f = let all_keys = List.dedup ~compare (List.append (Map.keys t1) (Map.keys t2)) in List.fold ~init:Map.Poly.empty all_keys ~f:(fun t key -> let z = match Map.find t1 key, Map.find t2 key with | None, None -> assert false | None, Some v2 -> `Right v2 | Some v1, None -> `Left v1 | Some v1, Some v2 -> `Both (v1, v2) in match f ~key z with | None -> t | Some data -> Map.add t ~key ~data) ;; let merge_test do_merge = let map2 = Int.Map.of_alist_exn (List.init size ~f:(fun i -> 2*i, 2*i)) in fun () -> ignore ( do_merge map map2 ~f:(fun ~key:_ x -> match x with | `Left a -> Some a | `Right a -> Some a | `Both (a, b) -> Some (a + b))) ;; let gen_diff_test m ~number_of_diff ~diff = let gen_pair i = sprintf "%6d" i, sprintf "%6d" (i+1) in let map1 = String.Map.of_alist_exn (List.init m ~f:gen_pair) in let map2 = let gen_pair i = gen_pair (i * 16856431 mod m) in List.fold (List.init number_of_diff ~f:gen_pair) ~init:map1 ~f:(fun acc (key, data) -> Map.add acc ~key ~data) in fun () -> let (_ : _ list) = diff map1 map2 ~data_equal:String.equal in () ;; let diff_by_iter2 map1 map2 ~data_equal = let results = ref [] in Map.iter2 map1 map2 ~f:(fun ~key ~data -> match data with | `Left _ -> results := (key, None) :: !results | `Right v -> results := (key, Some v) :: !results | `Both (v1, v2) -> if not (data_equal v1 v2) then results := (key, Some v2) :: !results ); !results ;; let command = let symmetric_diff t1 t2 ~data_equal = Map.symmetric_diff t1 t2 ~data_equal |> Sequence.to_list in Bench.make_command [ Test.create ~name:"Map.of_alist_exn" of_alist_exn; Test.create ~name:"Map.of_sorted_array" of_sorted_array; Test.create ~name:"Map.add" add; Test.create ~name:"Map.iter" iter; Test.create ~name:"Map.iter2" iter2; Test.create ~name:"Map.iter2_naive" iter2; Test.create ~name:"Map.remove" remove; Test.create ~name:"Map.merge (new)" (merge_test Map.merge); Test.create ~name:"Map.merge (old)" (merge_test old_map_merge); Test.create ~name:"Map.symmetric_diff-10" (gen_diff_test 100_000 ~number_of_diff:10 ~diff:symmetric_diff); Test.create ~name:"Map.symmetric_diff-100" (gen_diff_test 100_000 ~number_of_diff:100 ~diff:symmetric_diff); Test.create ~name:"Map.symmetric_diff-1000" (gen_diff_test 100_000 ~number_of_diff:1000 ~diff:symmetric_diff); Test.create ~name:"Map.symmetric_diff_by_iter2-10" (gen_diff_test 100_000 ~number_of_diff:10 ~diff:diff_by_iter2); Test.create ~name:"Map.symmetric_diff_by_iter2-100" (gen_diff_test 100_000 ~number_of_diff:100 ~diff:diff_by_iter2); Test.create ~name:"Map.symmetric_diff_by_iter2-1000" (gen_diff_test 100_000 ~number_of_diff:1000 ~diff:diff_by_iter2) ] ;; let () = Command.run command core-113.00.00/bench/core_stack.ml000066400000000000000000000012001256461075500164760ustar00rootroot00000000000000open Core.Std let _ = _squelch_unused_module_warning_ module Stack = Core.Std.Stack module Bench = Core_extended.Deprecated_bench let () = Bench.bench [ Bench.Test.create ~name:"Stack.fold" begin let s = Stack.of_list (List.init 100 ~f:Fn.id) in fun () -> ignore (Stack.fold s ~init:0 ~f:(+)) end; Bench.Test.create ~name:"stack_push_pop" begin let s = Stack.create () in Stack.push s (); fun () -> for _i = 1 to 10 do Stack.push s (); Stack.pop_exn s; done end ] ;; core-113.00.00/bench/core_string_search_pattern.ml000066400000000000000000000052571256461075500220010ustar00rootroot00000000000000open Core.Std open Core_bench.Std let rec x k = if k < 0 then "" else let b = x (k - 1) in String.concat ~sep:(String.of_char (Char.of_int_exn (65 + k))) [b; b] ;; let pat3 = x 3 let pat10 = x 10 let pat16 = x 16 let y k j = let c = x (k - 1) in String.concat ~sep:"$" ((List.init j ~f:(fun _ -> c)) @ [x k]) ;; let a p = fun () -> ignore (String.Search_pattern.create p) let b p = fun () -> ignore (Re2.Regex.create_exn p) let z p = fun () -> ignore (Pcre.regexp ~study:true p) let c h n = let z = Some (String.length h - String.length n) in let n = String.Search_pattern.create n in fun () -> assert (String.Search_pattern.index n ~in_:h = z) ;; let d h n = let n = Re2.Regex.create_exn n in fun () -> assert (Re2.Regex.matches n h) ;; let e h n = fun () -> assert (Core_extended.Extended_string.is_substring_deprecated ~substring:n h) ;; let f h n = let n = Pcre.regexp ~study:true n in fun () -> assert (Pcre.pmatch ~rex:n h) ;; let prefix s n = String.sub s ~pos:0 ~len:n let suffix s n = String.sub s ~pos:(String.length s - n) ~len:n let slow_create needle = (* Compute the longest prefix-suffix array from definition, O(n^3) *) let n = String.length needle in let kmp_arr = Array.create ~len:n (-1) in for i = 0 to n - 1 do let x = prefix needle (i + 1) in for j = 0 to i do if prefix x j = suffix x j then kmp_arr.(i) <- j done done; (needle, kmp_arr) ;; let () = Command.run ( Bench.make_command ( (* List.init 13 ~f:(fun k -> let x = x k in Bench.Test.create ~name:("slow_create_" ^ (Int.to_string (String.length x))) (fun () -> ignore (slow_create x))) @ *) List.concat ( List.map [3; 9; 12; 16] ~f:(fun k -> let x = x k in let kk = Int.to_string (String.length x) in [Bench.Test.create ~name:("kmp_create__" ^ kk) (a x); Bench.Test.create ~name:("re2_compile_" ^ kk) (b x); (* Bench.Test.create ~name:("pcre_compile_" ^ kk) (z x); *) ])) @ List.concat ( List.map [3; 9; (* 12 *)] ~f:(fun k -> let x = x k in let kk = Int.to_string (String.length x) in List.concat ( List.map [10; 100; (*300 *)] ~f:(fun j -> let y = y k j in let jj = Int.to_string (String.length y) in List.map [(c, "kmp_search_______"); (d, "re2_search_______"); (e, "mshinwell_search_"); (* (f, "pcre_search_"); *)] ~f:(fun (f, n) -> Bench.Test.create ~name:(n ^ kk ^ "_" ^ jj) (f y x)))))) )) ;; core-113.00.00/bench/dequeue.ml000066400000000000000000000005601256461075500160260ustar00rootroot00000000000000open Core.Std let _ = _squelch_unused_module_warning_ module Bench = Core_extended.Deprecated_bench let () = let d = Deque.create () in Deque.enqueue_front d (); Bench.bench [ Bench.Test.create ~name:"dequeue_push_pop" (fun () -> for _i = 1 to 10 do Deque.enqueue_front d (); Deque.dequeue_front_exn d; done); ] ;; core-113.00.00/bench/ordering_container.ml000066400000000000000000000071561256461075500202540ustar00rootroot00000000000000open Core.Std open Core_bench.Std module Heap = Heap.Removable module Int = struct let name = "int" include Int let random () = Random.int 1_000_000 end module String_list = struct let name = "string-list" module T = struct type t = string list with sexp, bin_io, compare let hash = Hashtbl.hash end include T include Comparable.Make(T) include Hashable.Make(T) let random_char () = Random.int 127 |> Char.of_int_exn let random () = List.init 5 ~f:(fun _ -> String.init 5 ~f:(fun _ -> random_char ())) end module type Key = sig type t include Hashable.S with type t := t include Comparable.S with type t := t val name : string val random : unit -> t end module Mock_heap = struct let create ~cmp:_ () = () let add_removable _ _ = () let update _ _ _ = () end let gen_test_add_and_update ~create ~random ~add ~update n = let sample = Array.init n ~f:(fun _ -> random ()) in let sample2 = Array.init n ~f:(fun _ -> random ()) in fun () -> let container = create () in Array.iter sample ~f:(fun x -> add container x); Array.iteri sample2 ~f:(fun i x -> update container sample.(i) x) let gen_test_update ~create ~random ~add ~update n = let sample = Array.init n ~f:(fun _ -> random ()) in let container = create () in Array.iter sample ~f:(fun x -> add container x); fun () -> for _i = 0 to n/10 do let i = Random.int n in let a = random () in update container sample.(i) a; sample.(i) <- a done let gen_tests m n = let module Key = (val m : Key) in let test_set = let random = Key.random in let create () = ref Key.Set.empty in let add c x = c := Set.add !c x in let update c x y = c := Set.add (Set.remove !c x) y in [ Bench.Test.create ~name:(Key.name ^ "-set-add&update") (gen_test_add_and_update ~create ~random ~add ~update n) ; Bench.Test.create ~name:(Key.name ^ "-set-update") (gen_test_update ~create ~random ~add ~update n) ] in let test_mock_heap = let module Heap = Mock_heap in let random = Key.random in let create () = Heap.create ~cmp:Key.compare (), Key.Table.create () in let add (heap, elts) x = let elt = Heap.add_removable heap x in Hashtbl.set elts ~key:x ~data:elt in let update (heap, elts) x y = match Hashtbl.find elts x with | None -> () | Some elt -> let elt = Heap.update heap elt y in Hashtbl.set elts ~key:y ~data:elt in [ Bench.Test.create ~name:(Key.name ^ "-mockheap-add&update") (gen_test_add_and_update ~create ~random ~add ~update n) ; Bench.Test.create ~name:(Key.name ^ "-mockheap-update") (gen_test_update ~create ~random ~add ~update n) ] in let test_heap = let random = Key.random in let create () = Heap.create ~cmp:Key.compare (), Key.Table.create () in let add (heap, elts) x = let elt = Heap.add_removable heap x in Hashtbl.set elts ~key:x ~data:elt in let update (heap, elts) x y = match Hashtbl.find elts x with | None -> () | Some elt -> let elt = Heap.update heap elt y in Hashtbl.set elts ~key:y ~data:elt in [ Bench.Test.create ~name:(Key.name ^ "-heap-add&update") (gen_test_add_and_update ~create ~random ~add ~update n) ; Bench.Test.create ~name:(Key.name ^ "-heap-update") (gen_test_update ~create ~random ~add ~update n) ] in List.concat [ test_set; test_heap; test_mock_heap ] let () = Random.self_init (); let n = 100_000 in [ gen_tests (module Int : Key) n ; gen_tests (module String_list : Key) n ] |> List.concat |> Bench.bench core-113.00.00/bench/string_escaping.ml000066400000000000000000000021531256461075500175500ustar00rootroot00000000000000open Core.Std module Bench = Core_extended.Deprecated_bench let () = let module E = String.Escaping in let escape = Staged.unstage (E.escape ~escapeworthy:['x';'y';'z'] ~escape_char:'\\') in let unescape = Staged.unstage (E.unescape ~escape_char:'\\') in let rex = Pcre.regexp "[xyz\\\\]" in let unrex = Pcre.regexp "\\\\." in let escape_pcre s = Pcre.substitute ~rex ~subst:(fun s -> "\\"^s) s in let unescape_pcre s = Pcre.substitute ~rex:unrex ~subst:(fun s -> Char.to_string s.[1]) s in let strings = [ "aaa" ; "xyz" ; "aaaaaaaaa" ; "aaxaaxaax" ; "abcde\\abcde\\abcde\\abcde\\abcde\\abcde\\" ; "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ; "aaaaaaaaaaaaaaaaaa\\aaaaaaaaaaaaaaaaaaaaaaa" ; "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ] in Bench.bench (List.concat_map strings ~f:(fun str -> let go name escape unescape = Bench.Test.create ~name:(sprintf "%s-%s" name str) (fun () -> assert (unescape (escape str) = str)) in [ go "String.Escaping" escape unescape ; go "Pcre" escape_pcre unescape_pcre ]) ) ;; core-113.00.00/bench/time_to_string.ml000066400000000000000000000004161256461075500174170ustar00rootroot00000000000000open Core.Std open Core_bench.Std let date = Date.create_exn ~d:14 ~m:Month.Jul ~y:1789 let () = Command.run (Bench.make_command [ Bench.Test.create ~name:"Date.to_string" (fun () -> ignore (Date.to_string date : string)) ]) ;; core-113.00.00/bench/timing_wheel.ml000066400000000000000000000053401256461075500170450ustar00rootroot00000000000000open Core.Std let ok_exn = Or_error.ok_exn let () = Sexp.of_int_style := `Underscores let user_plus_sys () = let { Unix.tms_utime; tms_stime; _ } = Unix.times () in sec (tms_utime +. tms_stime) ;; let log message a sexp_of_a = eprintf "%s\n%!" (Sexp.to_string_hum (Info.sexp_of_t (Info.create message a sexp_of_a))); ;; module Q = Timing_wheel.Priority_queue module Gc = Core.Std.Gc module Report = struct type t = { num_queue_elements : int; num_steps : int; user_plus_sys : Time.Span.t; nanoseconds_per_step : int; gc_stat : Gc.Stat.t; } with sexp_of end let test ~num_queue_elements ~num_steps = let q = Q.create ~level_bits:(Timing_wheel.Level_bits.create_exn [16]) () in let user_plus_sys_at_start = user_plus_sys () in for key = 1 to num_steps do ignore (Q.add q ~key:(Q.Key.of_int key) () : _ Q.Elt.t); if key > num_queue_elements then Q.increase_min_allowed_key q ~key:(Q.Key.of_int (key - num_queue_elements)) ~handle_removed:ignore; done; let user_plus_sys = Time.Span.(-) (user_plus_sys ()) user_plus_sys_at_start in let report = { Report. num_queue_elements; num_steps; user_plus_sys; nanoseconds_per_step = Float.iround_nearest_exn (Time.Span.to_ns user_plus_sys /. Float.of_int num_steps); gc_stat = Gc.stat (); } in log "report" report <:sexp_of< Report.t >> ;; (* Same as [test] but uses [Timing_wheel] instead of [Timing_wheel.Priority_queue]. This way all times are newly allocated floats. *) let test_with_allocations ~num_queue_elements ~num_steps = let tw = Timing_wheel.create ~config:(Timing_wheel.Config.create ~alarm_precision:Time.Span.millisecond ()) ~start:Time.epoch in let user_plus_sys_at_start = user_plus_sys () in let q : unit Timing_wheel.Alarm.t Queue.t = Queue.create () in for key = 1 to num_steps do Queue.enqueue q (Timing_wheel.add tw () ~at:(Time.of_float (float key /. float num_steps))); if key > num_queue_elements then Timing_wheel.advance_clock tw ~to_:(Time.of_float (float (key - num_queue_elements) /. float num_steps)) ~handle_fired:(fun _ -> ignore (Queue.dequeue_exn q)); done; let user_plus_sys = Time.Span.(-) (user_plus_sys ()) user_plus_sys_at_start in let report = { Report. num_queue_elements; num_steps; user_plus_sys; nanoseconds_per_step = Float.iround_nearest_exn (Time.Span.to_ns user_plus_sys /. Float.of_int num_steps); gc_stat = Gc.stat (); } in log "report" report <:sexp_of< Report.t >> ;; let () = ignore (test, test_with_allocations) let () = test ~num_queue_elements:2_048 ~num_steps:40_000_000; ;; core-113.00.00/bench/zone_next_clock_shift.ml000066400000000000000000000007631256461075500207570ustar00rootroot00000000000000open Core.Std open Core_bench.Std let zone = Time.Zone.find_exn "Europe/London" ;; (* on every half-hour in the year *) let times = let epoch = Time.of_string "2013-01-01 00:30:00+00:00" in List.map (List.range 0 (365 * 24)) ~f:(fun hr -> Time.add epoch (Time.Span.create ~hr ())) ;; Command.run (Bench.make_command [ Bench.Test.create ~name:"Time.Zone.next_clock_shift" (fun () -> List.iter times ~f:(fun time -> (ignore (Time.Zone.next_clock_shift zone ~after:time)))) ]);; core-113.00.00/config/000077500000000000000000000000001256461075500142245ustar00rootroot00000000000000core-113.00.00/config/detect.sh000077500000000000000000000015201256461075500160310ustar00rootroot00000000000000#!/bin/sh # Detect supported features and put the result in setup.data set -e if uname | grep -q -i linux; then linux_possible=true else linux_possible=false fi ptimer=`getconf _POSIX_TIMERS || echo undefined` case $ptimer in undefined) posix_timers_possible=false ;; *) if [ $ptimer -ge 200111 ]; then posix_timers_possible=true else posix_timers_possible=false fi ;; esac if ld -lrt -shared -o /dev/null 2>/dev/null; then rt_possible=true else rt_possible=false fi if [ -e setup.data ]; then sed '/^\(linux\|posix_timers\|rt\)_possible=/d' setup.data > setup.data.new mv setup.data.new setup.data fi cat >> setup.data <&2 exit 2 fi OCAMLC="$1" ML_OUTFILE="$2" C_OUTFILE="$3" shift 3 if [ ! -e setup.data ]; then echo "setup.data missing, run ./configure first." exit 2 fi OCAML_CFLAGS= . ./setup.data [ "$linux" = true ] && OCAML_CFLAGS="$OCAML_CFLAGS -ccopt -DLINUX_EXT" [ "$posix_timers" = true ] && OCAML_CFLAGS="$OCAML_CFLAGS -ccopt -DPOSIX_TIMERS" # it doesn't really matter whether this is bytecomp_c_compiler or native_c_compiler, it # just needs to be a C compiler CC="$bytecomp_c_compiler" MAKEFILE_CONFIG=`ocamlc -where`/Makefile.config if [ ! -e $MAKEFILE_CONFIG ]; then echo "Makefile.config missing in ocaml standard library path." echo 2 fi ARCH=`cat $MAKEFILE_CONFIG | grep '^ARCH=' | cut -d= -f2` WORDEXP=`{ echo '#include ' | cpp &> /dev/null && echo yes; } || echo no` SRC=config/test.c OUT=config/test.out trap "rm -f $OUT" EXIT $OCAMLC -ccopt -E $OCAML_CFLAGS -c $SRC | grep '^"OUT:[^"]*"$' | sed 's/"OUT:\([^"]*\)"/\1/' | tee > $OUT echo "DEFINE ARCH_$ARCH" >> $OUT if [ "$ARCH" = amd64 ]; then echo "DEFINE ARCH_x86_64" >> $OUT fi if [ "$WORDEXP" = yes ]; then echo "DEFINE WORDEXP" >> $OUT fi OCAML_VERSION="`ocamlc -version`" major=`echo $OCAML_VERSION | cut -d. -f1` minor=`echo $OCAML_VERSION | cut -d. -f2` if [ $major -ge 4 ]; then echo "DEFINE OCAML_4" >> $OUT [ $minor -ge 1 ] && echo "DEFINE OCAML_4_01" >> $OUT [ $minor -ge 2 ] && echo "DEFINE OCAML_4_02" >> $OUT fi # The recvmmsg system call was added in Linux 2.6.32 if $CC config/test_recvmmsg.c -o /dev/null 2> /dev/null; then echo "DEFINE RECVMMSG" >> $OUT; fi if $CC config/test_timerfd.c -o /dev/null 2> /dev/null; then echo "DEFINE TIMERFD" >> $OUT; fi for i in 1 2 3; do if $CC -I src -DJSC_STAT_NANOSEC_METHOD=$i config/test_nanosecond_stat.c -o /dev/null 2> /dev/null; then echo "DEFINE STAT_NANOSEC_METHOD = $i" >> $OUT break fi done mv "$OUT" "$ML_OUTFILE" { sentinel="CORE_`basename "$C_OUTFILE" | tr a-z. A-Z_`" cat < "$C_OUTFILE" core-113.00.00/config/test.c000066400000000000000000000034161256461075500153530ustar00rootroot00000000000000/* This file is just preprocessed. Lines of the form "OUT:XXX" are kept and replaced by XXX in the output to produce src/config.mlh. */ #include #include #include #include #include #if defined(LINUX_EXT) "OUT:DEFINE LINUX_EXT" #else # warning "cpp test --defined(LINUX_EXT)-- was false" # warning "Feature LINUX_EXT will not be available" #endif #if defined(POSIX_TIMERS) "OUT:DEFINE POSIX_TIMERS" #else # warning "cpp test --defined(POSIX_TIMERS)-- was false" # warning "Feature POSIX_TIMERS will not be available" #endif #if defined(RLIMIT_NICE) "OUT:DEFINE RLIMIT_NICE" #else # warning "cpp test --defined(RLIMIT_NICE)-- was false" # warning "Feature RLIMIT_NICE will not be available" #endif /* Defined in */ #if defined(ARCH_SIXTYFOUR) "OUT:DEFINE ARCH_SIXTYFOUR" #endif #if defined MSG_NOSIGNAL "OUT:DEFINE MSG_NOSIGNAL" #else # warning "cpp test --defined MSG_NOSIGNAL-- was false" # warning "Bigstring.(unsafe_|really_)?send(to)?(_noblocking)?_no_sigpipe will not be available" #endif #if defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS > 0) "OUT:DEFINE MUTEX_TIMED_LOCK" #else # warning "cpp test --defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS > 0)-- was false" # warning "Feature MUTEX_TIMED_LOCK will not be available" #endif #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 "OUT:DEFINE FDATASYNC" #else # warning "cpp test --defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0-- was false" # warning "Feature FDATASYNC will not be available" #endif #if defined(_POSIX_THREAD_CPUTIME) "OUT:DEFINE THREAD_CPUTIME" #else # warning "cpp test --defined(_POSIX_THREAD_CPUTIME)-- was false" # warning "Feature THREAD_CPUTIME will not be available" #endif core-113.00.00/config/test_nanosecond_stat.c000066400000000000000000000004141256461075500206100ustar00rootroot00000000000000#define _GNU_SOURCE #include #include #include #include "../src/nanosecond_stat.h" int main() { struct stat buf; double a, m, c; a = (double)buf.NSEC(a); m = (double)buf.NSEC(m); c = (double)buf.NSEC(c); return 0; } core-113.00.00/config/test_recvmmsg.c000066400000000000000000000002631256461075500172530ustar00rootroot00000000000000/* This file is only compiled to test the existence of the recvmmsg system call */ #define _GNU_SOURCE #include int main () { return recvmmsg(0, 0, 0, 0, 0); } core-113.00.00/config/test_timerfd.c000066400000000000000000000002461256461075500170630ustar00rootroot00000000000000#include int main() { int fd; struct itimerspec it; fd = timerfd_create(CLOCK_REALTIME, 0); timerfd_settime(fd, 0, &it, NULL); return 0; } core-113.00.00/configure000077500000000000000000000005531256461075500146710ustar00rootroot00000000000000#!/bin/sh # OASIS_START # DO NOT EDIT (digest: dc86c2ad450f91ca10c931b6045d0499) set -e FST=true for i in "$@"; do if $FST; then set -- FST=false fi case $i in --*=*) ARG=${i%%=*} VAL=${i##*=} set -- "$@" "$ARG" "$VAL" ;; *) set -- "$@" "$i" ;; esac done ocaml setup.ml -configure "$@" # OASIS_STOP core-113.00.00/core.install000066400000000000000000000000351256461075500152750ustar00rootroot00000000000000bin: ["corebuild" "coretop"] core-113.00.00/corebuild000077500000000000000000000005371256461075500146620ustar00rootroot00000000000000#!/bin/sh ocamlbuild \ -use-ocamlfind \ -syntax camlp4o \ -pkg core \ -pkg sexplib.syntax,comparelib.syntax,fieldslib.syntax,variantslib.syntax \ -pkg bin_prot.syntax \ -tag thread \ -tag debug \ -tag bin_annot \ -tag short_paths \ -cflags "-w A-4-33-40-41-42-43-34-44" \ -cflags -strict-sequence \ $@ core-113.00.00/coretop000077500000000000000000000000701256461075500143550ustar00rootroot00000000000000#!/bin/sh exec utop -require core.top,core.syntax "$@" core-113.00.00/example/000077500000000000000000000000001256461075500144125ustar00rootroot00000000000000core-113.00.00/example/command/000077500000000000000000000000001256461075500160305ustar00rootroot00000000000000core-113.00.00/example/command/main.ml000066400000000000000000000205451256461075500173140ustar00rootroot00000000000000open Core.Std module Command = Core.Std.Command (* BEGIN -- useful utilities *) include struct open Async.Std let uses_async : (unit -> int Deferred.t, unit -> unit) Command.Spec.t = Command.Spec.step (fun finished () -> printf "uses_async\n%!"; upon (finished ()) Shutdown.shutdown; let () = never_returns (Scheduler.go ()) in ()) end let flag_prompt_if_missing name of_string ~doc = let open Command.Spec in let arg = Arg_type.create of_string in map (flag ("-" ^ name) (optional arg) ~doc) ~f:(function | Some v -> v | None -> printf "enter %s: %!" name; match In_channel.input_line stdin with | None -> failwith "no value entered. aborting." | Some line -> (of_string line) ) let fields_flag spec ~doc s field = let open Command.Spec in let name = Fieldslib.Field.name field in let name = String.tr ~target:'_' ~replacement:'-' name in s +> flag ("-" ^ name) spec ~doc (* END -- useful utilities *) module Sing = struct module Note = struct type t = A | B | C | D | E | F | G with sexp let of_string x = t_of_sexp (Sexp.Atom x) let arg_type = Command.Spec.Arg_type.create of_string end let command = Command.basic ~summary:"sing a song" Command.Spec.( (* flags *) step (fun k slow -> k ~slow) +> flag "slow" ~aliases:["AA";"-BB"] no_arg ~doc:" sing slow" +> flag "-loudness" (optional int) ~doc:"N how loud to sing (number of decibels)" +> flag "-date" (optional date) ~doc:"DATE the date" +> flag "-note" (listed Note.arg_type) ~doc:"NOTE a note" (* anonymous arguments *) +> anon ("NAME" %: string) +> anon ("FOO" %: string) +> anon (sequence ("BAR" %: string)) ) (fun ~slow loudness date notes song _ _ () -> (* ... your code here... *) print_endline (if slow then "slow" else "fast"); printf "loudness = %s\n" (Option.value ~default:"none" (Option.map ~f:Int.to_string loudness)); printf "date = %s\n" (Option.value ~default:"no date" (Option.map date ~f:Date.to_string)); printf "song name = %s\n" song; List.iter notes ~f:(fun note -> print_endline (Sexp.to_string_hum ( Sexp.List [Sexp.Atom "note"; Note.sexp_of_t note]))) ) end let revision_flag = let open Command.Spec in flag "-revision" ~doc:"REV revision number" (required string) module Hg_log = struct let command = Command.basic ~summary:"show a point in hg history" Command.Spec.( empty +> revision_flag +> flag "-print" no_arg ~doc:" display all changes (not just a summary)") (fun revision print () -> (* ... your code here ... *) ignore (revision, print) ) end module Hg_cat = struct let command = Command.basic ~summary:"cat a file from hg history" Command.Spec.(empty +> revision_flag +> anon ("FILE" %: string)) (fun revision file () -> (* ... your code here ... *) ignore (revision, file) ) end module Cat = struct open Async.Std let command = Command.basic ~summary:"example async command: cat a file to stdout" Command.Spec.(empty +> anon ("FILE" %: string) ++ uses_async) (fun path () -> Reader.with_file path ~f:(fun r -> Pipe.iter_without_pushback (Reader.pipe r) ~f:(fun chunk -> Writer.write (Lazy.force Writer.stdout) chunk)) >>= fun _ -> return 0) end module Prompting = struct let command = Command.basic ~summary:"command demonstrating prompt-if-missing flags" Command.Spec.( (* flags *) empty +> flag "-rev" (required string) ~doc:" print stuff" +> flag_prompt_if_missing "id" Fn.id ~doc:" whatever" ) (fun revision id () -> (* ... your code here ... *) print_endline "MAIN STARTED"; printf "revision = %s\n%!" revision; printf "id = %s\n%!" id ) end module Fields = struct type t = { foo : int; bar : string option; baz : float list; } with fields, sexp let main t = (* ... your code here ... *) print_endline (Sexp.to_string_hum (sexp_of_t t)) let command = Command.basic ~summary:"example using fieldslib" Command.Spec.( Fields.fold ~init:(step Fn.id) ~foo:(fields_flag (required int) ~doc:"N foo factor") ~bar:(fields_flag (optional string) ~doc:"B error bar (optional)") ~baz:(fields_flag (listed float) ~doc:"X whatever (listed)")) (fun foo bar baz () -> main {foo; bar; baz}) end module Fields_with_default = struct type t = { foo : int; bar : string option; baz : float list; } with fields, sexp let default = { foo = 1; bar = None; baz = []; } let main t () = (* ... your code here ... *) print_endline (Sexp.to_string_hum (sexp_of_t t)) let fields_flag spec ~doc acc field = let name = Fieldslib.Field.name field in let name = String.tr ~target:'_' ~replacement:'-' name in let f main (record:t) value = main (Fieldslib.Field.fset field record value) in let open Command.Spec in step f ++ acc +> flag ("-" ^ name) spec ~doc let command = Command.basic ~summary:"example using fieldslib" Command.Spec.( Fields.fold ~init:(empty +> const default) ~foo:(fields_flag (required int) ~doc:"N foo factor") ~bar:(fields_flag (optional string) ~doc:"B error bar (optional)") ~baz:(fields_flag (listed float) ~doc:"X whatever (listed)")) main end module Complex_anons = struct let command = Command.basic ~summary:"command with complex anonymous argument structure" Command.Spec.( empty +> anon ("A" %: string) +> anon ("B" %: string) +> anon (maybe (t3 ("C" %: string) ("D" %: string) (maybe (t3 ("E" %: string) ("F" %: string) (sequence ("G" %: string)))))) ) (fun a b rest () -> (* ... your code here... *) printf "A = %s\n" a; printf "B = %s\n" b; Option.iter rest ~f:(fun (c, d, rest) -> printf "C = %s\n" c; printf "D = %s\n" d; Option.iter rest ~f:(fun (e, f, gs) -> printf "E = %s\n" e; printf "F = %s\n" f; List.iter gs ~f:(fun g -> printf "G = %s\n" g; ) ) ) ) end module Goodies = struct let command = Command.basic ~summary:"demo of how to get various backdoor values" Command.Spec.( empty +> help +> path +> args +> flag "t" (optional string) ~doc:"" +> flag "-fail" no_arg ~doc:" die, die, die!" ) (fun help path args _ _ () -> print_endline "PATH:"; List.iter path ~f:(fun x -> print_endline (" " ^ x)); print_endline "ARGS:"; List.iter args ~f:(fun x -> print_endline (" " ^ x)); print_endline "HELP!"; print_endline (Lazy.force help) ) end module Long_flag_description = struct let command = Command.basic ~summary:"demo of word wrap for long flag descriptions" Command.Spec.( empty +> flag "-foo" no_arg ~doc:" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus fermentum condimentum eros, sit amet pulvinar dui ultrices in." ) (fun _ () -> ()) end module Command_dot_exec = struct let command = Command.exec ~summary:"example usage of [Command.exec]" ~path_to_exe:(`Relative_to_me "main_no_recur.exe") () end let command = let commands = [ ("sing", Sing.command) ; ("hg", Command.group ~summary:"commands sharing a flag specification" [ ("log", Hg_log.command) ; ("cat", Hg_cat.command) ]) ; ("cat", Cat.command) ; ("prompting", Prompting.command) ; ("fields", Fields.command) ; ("fields-with-default", Fields_with_default.command) ; ("complex-anons", Complex_anons.command) ; ("sub", Command.group ~summary:"a subcommand" [ ("goodies", Goodies.command) ]) ; ("long-flag-description", Long_flag_description.command) ; ("command-dot-exec", Command_dot_exec.command) ] in Command.group ~summary:"command examples" commands ;; let () = Command.run command core-113.00.00/example/command/main.mli000066400000000000000000000000011256461075500174460ustar00rootroot00000000000000 core-113.00.00/example/command/main_no_recur.ml000066400000000000000000000005631256461075500212060ustar00rootroot00000000000000open Core.Std let command = Command.basic ~summary:"demo of word wrap for long flag descriptions" Command.Spec.( empty +> flag "-foo" no_arg ~doc:" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus fermentum condimentum eros, sit amet pulvinar dui ultrices in." ) (fun _ () -> ()) let () = Command.run command core-113.00.00/example/quickcheck/000077500000000000000000000000001256461075500165245ustar00rootroot00000000000000core-113.00.00/example/quickcheck/from_comments.ml000066400000000000000000000005661256461075500217350ustar00rootroot00000000000000open Core.Std open Quickcheck.Observer type 'a bst = Leaf | Node of 'a bst * 'a * 'a bst let bst_obs key_obs = recursive (fun bst_of_key_obs -> unmap (either unit (tuple3 bst_of_key_obs key_obs bst_of_key_obs)) ~f:(function | Leaf -> First () | Node (l, k, r) -> Second (l, k, r)) ~f_sexp:(fun () -> Sexp.Atom "either_of_bst")) core-113.00.00/example/quickcheck/from_docs.ml000066400000000000000000000253761256461075500210460ustar00rootroot00000000000000open Core.Std open Quickcheck module Initial_example = struct TEST_UNIT "fold_left vs fold_right" = Quickcheck.test Generator.(list int) ~sexp_of:<:sexp_of< int list >> ~f:(fun list -> <:test_eq< int >> (List.fold_left ~init:0 ~f:(+) list) (List.fold_right ~init:0 ~f:(+) list)) end module Generator_examples = struct let (_ : _ Generator.t) = Generator.singleton "An arbitrary value." let (_ : _ Generator.t) = Generator.string (* any string, including weird strings like "\000" *) let (_ : _ Generator.t) = Generator.int (* any int, from [min_value] to [max_value] *) let (_ : _ Generator.t) = Generator.float (* any float, from [neg_infinity] to [infinity] plus [nan] *) let (_ : _ Generator.t) = Generator.size (* small non-negative ints *) let (_ : _ Generator.t) = Generator.int_between ~lower_bound:(Incl 0) ~upper_bound:(Excl 100) let (_ : _ Generator.t) = Generator.float_between ~lower_bound:(Incl 1.) ~upper_bound:Unbounded ~nan:Without let (_ : _ Generator.t) = Generator.(tuple2 int float) let (_ : _ Generator.t) = Generator.(list (tuple2 int float)) let (_ : _ Generator.t) = Generator.(list (tuple2 int float) ~unique:true ~length:(`At_most 12) ~sorted:(`By <:compare< int * float >>)) let (_ : _ Generator.t) = Generator.(either int float) let (_ : _ Generator.t) = Generator.(option string) let (_ : _ Generator.t) = Generator.(map char ~f:Char.to_int) let (_ : _ Generator.t) = Generator.(filter float ~f:Float.is_finite) (* use [filter] sparingly! *) let (_ : _ Generator.t) = Generator.(fn Observer.int bool) let (_ : _ Generator.t) = Generator.(union [ singleton (Ok ()) ; singleton (Or_error.error_string "fail") ]) module Monadic = struct let (_ : _ Generator.t) = let open Generator in string >>= fun str -> int_between ~lower_bound:(Incl 0) ~upper_bound:(Excl (String.length str)) >>| fun i -> str, i, String.get str i end module Recursive = struct let (_ : _ Generator.t) = Generator.(recursive (fun sexp -> either string (list sexp) >>| function | First a -> Sexp.Atom a | Second l -> Sexp.List l)) let rec binary_subtree ~lower_bound ~upper_bound = let open Generator in union [ singleton `Leaf ; int_between ~lower_bound ~upper_bound >>= fun key -> binary_subtree ~lower_bound ~upper_bound:(Excl key) >>= fun left -> binary_subtree ~lower_bound:(Excl key) ~upper_bound >>| fun right -> `Node (left, key, right) ] let _binary_tree () : _ Generator.t = binary_subtree ~lower_bound:Unbounded ~upper_bound:Unbounded let rec powers_of_two_starting_from x = let open Generator in union [ singleton x ; of_fun (fun () -> powers_of_two_starting_from (x *. 2.)) ] let _powers_of_two : _ Generator.t = powers_of_two_starting_from 1. end end module Observer_examples = struct let (_ : _ Observer.t) = Observer.singleton () let (_ : _ Observer.t) = Observer.string let (_ : _ Observer.t) = Observer.int let (_ : _ Observer.t) = Observer.float let (_ : _ Observer.t) = Observer.(tuple2 int float) let (_ : _ Observer.t) = Observer.(list (tuple2 int float)) let (_ : _ Observer.t) = Observer.(either int float) let (_ : _ Observer.t) = Observer.(option string) let (_ : _ Observer.t) = Observer.(fn Generator.int bool ~sexp_of_dom:<:sexp_of< int >>) let (_ : _ Observer.t) = Observer.(unmap char ~f:Char.of_int_exn ~f_sexp:(fun () -> Sexp.Atom "Char.of_int_exn")) end module Example_1_functional = struct module Functional_stack : sig type 'a t with sexp, compare val empty : _ t val is_empty : _ t -> bool val push : 'a t -> 'a -> 'a t val top_exn : 'a t -> 'a val pop_exn : 'a t -> 'a t end = struct type 'a t = 'a list with sexp, compare let empty = [] let is_empty = List.is_empty let push t x = x :: t let top_exn = function | [] -> failwith "empty stack" | x :: _ -> x let pop_exn = function | [] -> failwith "empty stack" | _ :: t -> t end let stack elt = Generator.(recursive (fun self -> either unit (tuple2 elt self) >>| function | First () -> Functional_stack.empty | Second (x, t) -> Functional_stack.push t x)) open Functional_stack TEST_UNIT "push + is_empty" = Quickcheck.test Generator.(tuple2 int (stack int)) ~f:(fun (x, t) -> <:test_result< bool >> (is_empty (push t x)) ~expect:false) TEST_UNIT "push + top_exn" = Quickcheck.test Generator.(tuple2 int (stack int)) ~f:(fun (x, t) -> <:test_result< int >> (top_exn (push t x)) ~expect:x) TEST_UNIT "push + pop_exn" = Quickcheck.test Generator.(tuple2 int (stack int)) ~f:(fun (x, t) -> <:test_result< int t >> (pop_exn (push t x)) ~expect:t) end module Example_2_imperative = struct module Imperative_stack : sig type 'a t with sexp, compare val create : unit -> _ t val is_empty : _ t -> bool val push : 'a t -> 'a -> unit val pop_exn : 'a t -> 'a val iter : 'a t -> f:('a -> unit) -> unit val to_list : 'a t -> 'a list end = struct type 'a t = 'a list ref with sexp, compare let create () = ref [] let is_empty t = List.is_empty !t let push t x = t := x :: !t let pop_exn t = match !t with | [] -> failwith "empty stack" | x :: list -> t := list; x let to_list t = !t let iter t ~f = List.iter !t ~f end let stack elt = let open Generator in list elt >>| fun xs -> let t = Imperative_stack.create () in List.iter xs ~f:(fun x -> Imperative_stack.push t x); t open Imperative_stack TEST_UNIT "push + is_empty" = Quickcheck.test Generator.(tuple2 string (stack string)) ~f:(fun (x, t) -> <:test_result< bool >> (push t x; is_empty t) ~expect:false) TEST_UNIT "push + pop_exn" = Quickcheck.test Generator.(tuple2 string (stack string)) ~f:(fun (x, t) -> push t x; let y = pop_exn t in <:test_result< string >> y ~expect:x) TEST_UNIT "push + to_list" = Quickcheck.test Generator.(tuple2 string (stack string)) ~f:(fun (x, t) -> let list1 = to_list t in push t x; let list2 = to_list t in <:test_result< string list >> list2 ~expect:(x :: list1)) TEST_UNIT "push + pop_exn + to_list" = Quickcheck.test Generator.(tuple2 string (stack string)) ~f:(fun (x, t) -> let list1 = to_list t in push t x; let _ = pop_exn t in let list2 = to_list t in <:test_result< string list >> list2 ~expect:list1) TEST_UNIT "iter" = Quickcheck.test Generator.(stack string) ~f:(fun t -> let q = Queue.create () in iter t ~f:(fun x -> Queue.enqueue q x); <:test_result< string list >> (Queue.to_list q) ~expect:(to_list t)) end module Example_3_asynchronous = struct open Async.Std module Async_stack : sig type 'a t with sexp, compare val create : unit -> _ t val is_empty : 'a t -> bool val push : 'a t -> 'a -> unit Deferred.t (* pushback until stack empties *) val pop : 'a t -> 'a Deferred.t (* wait until element is available *) val iter : 'a t -> f:('a -> unit Deferred.t) -> unit Deferred.t val to_list : 'a t -> 'a list end = struct type 'a t = { mutable elts : 'a list ; mutable push : unit Ivar.t ; mutable pops : 'a Ivar.t list } let of_list elts = { elts ; push = if List.is_empty elts then Ivar.create_full () else Ivar.create () ; pops = [] } let to_list t = t.elts let sexp_of_t sexp_of_elt t = <:sexp_of< elt list >> (to_list t) let t_of_sexp elt_of_sexp sexp = of_list (<:of_sexp< elt list >> sexp) let compare (type elt) compare_elt t1 t2 = <:compare< elt list >> t1.elts t2.elts let create () = of_list [] let is_empty t = List.is_empty t.elts let push_without_pushback t x = match t.pops with | ivar :: rest -> t.pops <- rest; Ivar.fill ivar x | [] -> if Ivar.is_full t.push then t.push <- Ivar.create (); t.elts <- x :: t.elts let push t x = push_without_pushback t x; Ivar.read t.push let pop t = match t.elts with | [] -> let ivar = Ivar.create () in t.pops <- ivar :: t.pops; Ivar.read ivar | x :: rest -> t.elts <- rest; if List.is_empty rest then Ivar.fill t.push (); Deferred.return x let iter t ~f = Deferred.List.iter t.elts ~f end let stack elt = let open Generator in list elt >>| fun xs -> let t = Async_stack.create () in List.iter xs ~f:(fun x -> don't_wait_for (Async_stack.push t x)); t open Async_stack TEST_UNIT "push + is_empty" = Quickcheck.test Generator.(tuple2 char (stack char)) ~f:(fun (x, t) -> don't_wait_for (push t x); <:test_result< bool >> (is_empty t) ~expect:false) TEST_UNIT "push + to_list" = Quickcheck.test Generator.(tuple2 char (stack char)) ~f:(fun (x, t) -> let list1 = to_list t in don't_wait_for (push t x); let list2 = to_list t in <:test_result< char list >> list2 ~expect:(x :: list1)) TEST_UNIT "push + pushback" = Quickcheck.test Generator.(tuple2 char (stack char)) ~f:(fun (x, t) -> let pushback = push t x in <:test_result< bool >> (Deferred.is_determined pushback) ~expect:false) TEST_UNIT "push + pop" = Thread_safe.block_on_async_exn (fun () -> Quickcheck.async_test Generator.(tuple2 char (stack char)) ~f:(fun (x, t) -> don't_wait_for (push t x); pop t >>| fun y -> <:test_result< char >> y ~expect:x)) TEST_UNIT "push + pop + to_list" = Thread_safe.block_on_async_exn (fun () -> Quickcheck.async_test Generator.(tuple2 char (stack char)) ~f:(fun (x, t) -> let list1 = to_list t in don't_wait_for (push t x); pop t >>| fun _ -> let list2 = to_list t in <:test_result< char list >> list2 ~expect:list1)) TEST_UNIT "iter" = Thread_safe.block_on_async_exn (fun () -> Quickcheck.async_test Generator.(stack char) ~f:(fun t -> let q = Queue.create () in iter t ~f:(fun x -> Queue.enqueue q x; Deferred.unit) >>| fun () -> <:test_result< char list >> (Queue.to_list q) ~expect:(to_list t))) TEST_UNIT "push + pop + pushback" = Thread_safe.block_on_async_exn (fun () -> Quickcheck.async_test Generator.(tuple2 char (stack char)) ~f:(fun (x, t) -> let pushback = push t x in pop t >>| fun _ -> <:test_result< bool >> (Deferred.is_determined pushback) ~expect:(is_empty t))) end core-113.00.00/example/quickcheck/from_wiki.ml000066400000000000000000000020621256461075500210440ustar00rootroot00000000000000open Core.Std open Quickcheck TEST_UNIT "count vs length" = Quickcheck.test (* (\* Initial example that fails on NaN: *\) * Generator.(list float) *) (* Working example that filters out NaN: *) Generator.(list (float_between ~lower_bound:(Incl Float.neg_infinity) ~upper_bound:(Incl Float.infinity) ~nan:Without)) (* (\* Alternate version of filtering out NaN: *\) * Generator.(list (filter float ~f:(Fn.non Float.is_nan))) *) ~sexp_of:<:sexp_of< float list >> ~f:(fun float_list -> <:test_result< int >> (List.count float_list ~f:(fun x -> x = x)) ~expect:(List.length float_list)) let list_gen elt_gen = Generator.(recursive (fun list_gen -> variant2 unit (tuple2 elt_gen list_gen) >>| function | `A () -> [] | `B (head, tail) -> head :: tail)) let sexp_gen = Generator.(recursive (fun sexp_gen -> variant2 string (list_gen sexp_gen) >>| function | `A atom -> Sexp.Atom atom | `B list -> Sexp.List list)) core-113.00.00/example/unix/000077500000000000000000000000001256461075500153755ustar00rootroot00000000000000core-113.00.00/example/unix/gettid.ml000066400000000000000000000011631256461075500172100ustar00rootroot00000000000000open Core.Std open Async.Std module Unix = Core.Std.Unix let gettid_exn () = Or_error.ok_exn Unix.gettid () ;; let main () = Core.Std.Printf.printf "top -Hp %s\n%!" (Pid.to_string (Unix.getpid ())); Clock.after (sec 5.) >>= fun () -> Clock.every (sec 1.) (fun () -> don't_wait_for (In_thread.run (fun () -> Core.Std.Printf.printf "%d\n%!" (Unix.Thread_id.to_int (gettid_exn ())); (* wait for a little while, to force more than one thread to be used *) Unix.sleep 5 ))); Deferred.never () ;; Command.async ~summary:"demonstrate thread ID call" Command.Spec.empty main |> Command.run core-113.00.00/myocamlbuild.ml000066400000000000000000000447261256461075500160070ustar00rootroot00000000000000(* OASIS_START *) (* DO NOT EDIT (digest: 10ed83e3abed6116c892bdad5ecd46cf) *) module OASISGettext = struct (* # 22 "src/oasis/OASISGettext.ml" *) let ns_ str = str let s_ str = str let f_ (str: ('a, 'b, 'c, 'd) format4) = str let fn_ fmt1 fmt2 n = if n = 1 then fmt1^^"" else fmt2^^"" let init = [] end module OASISExpr = struct (* # 22 "src/oasis/OASISExpr.ml" *) open OASISGettext type test = string type flag = string type t = | EBool of bool | ENot of t | EAnd of t * t | EOr of t * t | EFlag of flag | ETest of test * string type 'a choices = (t * 'a) list let eval var_get t = let rec eval' = function | EBool b -> b | ENot e -> not (eval' e) | EAnd (e1, e2) -> (eval' e1) && (eval' e2) | EOr (e1, e2) -> (eval' e1) || (eval' e2) | EFlag nm -> let v = var_get nm in assert(v = "true" || v = "false"); (v = "true") | ETest (nm, vl) -> let v = var_get nm in (v = vl) in eval' t let choose ?printer ?name var_get lst = let rec choose_aux = function | (cond, vl) :: tl -> if eval var_get cond then vl else choose_aux tl | [] -> let str_lst = if lst = [] then s_ "" else String.concat (s_ ", ") (List.map (fun (cond, vl) -> match printer with | Some p -> p vl | None -> s_ "") lst) in match name with | Some nm -> failwith (Printf.sprintf (f_ "No result for the choice list '%s': %s") nm str_lst) | None -> failwith (Printf.sprintf (f_ "No result for a choice list: %s") str_lst) in choose_aux (List.rev lst) end # 132 "myocamlbuild.ml" module BaseEnvLight = struct (* # 22 "src/base/BaseEnvLight.ml" *) module MapString = Map.Make(String) type t = string MapString.t let default_filename = Filename.concat (Sys.getcwd ()) "setup.data" let load ?(allow_empty=false) ?(filename=default_filename) () = if Sys.file_exists filename then begin let chn = open_in_bin filename in let st = Stream.of_channel chn in let line = ref 1 in let st_line = Stream.from (fun _ -> try match Stream.next st with | '\n' -> incr line; Some '\n' | c -> Some c with Stream.Failure -> None) in let lexer = Genlex.make_lexer ["="] st_line in let rec read_file mp = match Stream.npeek 3 lexer with | [Genlex.Ident nm; Genlex.Kwd "="; Genlex.String value] -> Stream.junk lexer; Stream.junk lexer; Stream.junk lexer; read_file (MapString.add nm value mp) | [] -> mp | _ -> failwith (Printf.sprintf "Malformed data file '%s' line %d" filename !line) in let mp = read_file MapString.empty in close_in chn; mp end else if allow_empty then begin MapString.empty end else begin failwith (Printf.sprintf "Unable to load environment, the file '%s' doesn't exist." filename) end let rec var_expand str env = let buff = Buffer.create ((String.length str) * 2) in Buffer.add_substitute buff (fun var -> try var_expand (MapString.find var env) env with Not_found -> failwith (Printf.sprintf "No variable %s defined when trying to expand %S." var str)) str; Buffer.contents buff let var_get name env = var_expand (MapString.find name env) env let var_choose lst env = OASISExpr.choose (fun nm -> var_get nm env) lst end # 237 "myocamlbuild.ml" module MyOCamlbuildFindlib = struct (* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *) (** OCamlbuild extension, copied from * http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild * by N. Pouillard and others * * Updated on 2009/02/28 * * Modified by Sylvain Le Gall *) open Ocamlbuild_plugin type conf = { no_automatic_syntax: bool; } (* these functions are not really officially exported *) let run_and_read = Ocamlbuild_pack.My_unix.run_and_read let blank_sep_strings = Ocamlbuild_pack.Lexers.blank_sep_strings let exec_from_conf exec = let exec = let env_filename = Pathname.basename BaseEnvLight.default_filename in let env = BaseEnvLight.load ~filename:env_filename ~allow_empty:true () in try BaseEnvLight.var_get exec env with Not_found -> Printf.eprintf "W: Cannot get variable %s\n" exec; exec in let fix_win32 str = if Sys.os_type = "Win32" then begin let buff = Buffer.create (String.length str) in (* Adapt for windowsi, ocamlbuild + win32 has a hard time to handle '\\'. *) String.iter (fun c -> Buffer.add_char buff (if c = '\\' then '/' else c)) str; Buffer.contents buff end else begin str end in fix_win32 exec let split s ch = let buf = Buffer.create 13 in let x = ref [] in let flush () = x := (Buffer.contents buf) :: !x; Buffer.clear buf in String.iter (fun c -> if c = ch then flush () else Buffer.add_char buf c) s; flush (); List.rev !x let split_nl s = split s '\n' let before_space s = try String.before s (String.index s ' ') with Not_found -> s (* ocamlfind command *) let ocamlfind x = S[Sh (exec_from_conf "ocamlfind"); x] (* This lists all supported packages. *) let find_packages () = List.map before_space (split_nl & run_and_read (exec_from_conf "ocamlfind" ^ " list")) (* Mock to list available syntaxes. *) let find_syntaxes () = ["camlp4o"; "camlp4r"] let well_known_syntax = [ "camlp4.quotations.o"; "camlp4.quotations.r"; "camlp4.exceptiontracer"; "camlp4.extend"; "camlp4.foldgenerator"; "camlp4.listcomprehension"; "camlp4.locationstripper"; "camlp4.macro"; "camlp4.mapgenerator"; "camlp4.metagenerator"; "camlp4.profiler"; "camlp4.tracer" ] let dispatch conf = function | After_options -> (* By using Before_options one let command line options have an higher * priority on the contrary using After_options will guarantee to have * the higher priority override default commands by ocamlfind ones *) Options.ocamlc := ocamlfind & A"ocamlc"; Options.ocamlopt := ocamlfind & A"ocamlopt"; Options.ocamldep := ocamlfind & A"ocamldep"; Options.ocamldoc := ocamlfind & A"ocamldoc"; Options.ocamlmktop := ocamlfind & A"ocamlmktop"; Options.ocamlmklib := ocamlfind & A"ocamlmklib" | After_rules -> (* When one link an OCaml library/binary/package, one should use * -linkpkg *) flag ["ocaml"; "link"; "program"] & A"-linkpkg"; if not (conf.no_automatic_syntax) then begin (* For each ocamlfind package one inject the -package option when * compiling, computing dependencies, generating documentation and * linking. *) List.iter begin fun pkg -> let base_args = [A"-package"; A pkg] in (* TODO: consider how to really choose camlp4o or camlp4r. *) let syn_args = [A"-syntax"; A "camlp4o"] in let (args, pargs) = (* Heuristic to identify syntax extensions: whether they end in ".syntax"; some might not. *) if Filename.check_suffix pkg "syntax" || List.mem pkg well_known_syntax then (syn_args @ base_args, syn_args) else (base_args, []) in flag ["ocaml"; "compile"; "pkg_"^pkg] & S args; flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S args; flag ["ocaml"; "doc"; "pkg_"^pkg] & S args; flag ["ocaml"; "link"; "pkg_"^pkg] & S base_args; flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S args; (* TODO: Check if this is allowed for OCaml < 3.12.1 *) flag ["ocaml"; "compile"; "package("^pkg^")"] & S pargs; flag ["ocaml"; "ocamldep"; "package("^pkg^")"] & S pargs; flag ["ocaml"; "doc"; "package("^pkg^")"] & S pargs; flag ["ocaml"; "infer_interface"; "package("^pkg^")"] & S pargs; end (find_packages ()); end; (* Like -package but for extensions syntax. Morover -syntax is useless * when linking. *) List.iter begin fun syntax -> flag ["ocaml"; "compile"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; flag ["ocaml"; "ocamldep"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; flag ["ocaml"; "doc"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; flag ["ocaml"; "infer_interface"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; end (find_syntaxes ()); (* The default "thread" tag is not compatible with ocamlfind. * Indeed, the default rules add the "threads.cma" or "threads.cmxa" * options when using this tag. When using the "-linkpkg" option with * ocamlfind, this module will then be added twice on the command line. * * To solve this, one approach is to add the "-thread" option when using * the "threads" package using the previous plugin. *) flag ["ocaml"; "pkg_threads"; "compile"] (S[A "-thread"]); flag ["ocaml"; "pkg_threads"; "doc"] (S[A "-I"; A "+threads"]); flag ["ocaml"; "pkg_threads"; "link"] (S[A "-thread"]); flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"]); flag ["ocaml"; "package(threads)"; "compile"] (S[A "-thread"]); flag ["ocaml"; "package(threads)"; "doc"] (S[A "-I"; A "+threads"]); flag ["ocaml"; "package(threads)"; "link"] (S[A "-thread"]); flag ["ocaml"; "package(threads)"; "infer_interface"] (S[A "-thread"]); | _ -> () end module MyOCamlbuildBase = struct (* # 22 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *) (** Base functions for writing myocamlbuild.ml @author Sylvain Le Gall *) open Ocamlbuild_plugin module OC = Ocamlbuild_pack.Ocaml_compiler type dir = string type file = string type name = string type tag = string (* # 62 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *) type t = { lib_ocaml: (name * dir list * string list) list; lib_c: (name * dir * file list) list; flags: (tag list * (spec OASISExpr.choices)) list; (* Replace the 'dir: include' from _tags by a precise interdepends in * directory. *) includes: (dir * dir list) list; } let env_filename = Pathname.basename BaseEnvLight.default_filename let dispatch_combine lst = fun e -> List.iter (fun dispatch -> dispatch e) lst let tag_libstubs nm = "use_lib"^nm^"_stubs" let nm_libstubs nm = nm^"_stubs" let dispatch t e = let env = BaseEnvLight.load ~filename:env_filename ~allow_empty:true () in match e with | Before_options -> let no_trailing_dot s = if String.length s >= 1 && s.[0] = '.' then String.sub s 1 ((String.length s) - 1) else s in List.iter (fun (opt, var) -> try opt := no_trailing_dot (BaseEnvLight.var_get var env) with Not_found -> Printf.eprintf "W: Cannot get variable %s\n" var) [ Options.ext_obj, "ext_obj"; Options.ext_lib, "ext_lib"; Options.ext_dll, "ext_dll"; ] | After_rules -> (* Declare OCaml libraries *) List.iter (function | nm, [], intf_modules -> ocaml_lib nm; let cmis = List.map (fun m -> (String.uncapitalize m) ^ ".cmi") intf_modules in dep ["ocaml"; "link"; "library"; "file:"^nm^".cma"] cmis | nm, dir :: tl, intf_modules -> ocaml_lib ~dir:dir (dir^"/"^nm); List.iter (fun dir -> List.iter (fun str -> flag ["ocaml"; "use_"^nm; str] (S[A"-I"; P dir])) ["compile"; "infer_interface"; "doc"]) tl; let cmis = List.map (fun m -> dir^"/"^(String.uncapitalize m)^".cmi") intf_modules in dep ["ocaml"; "link"; "library"; "file:"^dir^"/"^nm^".cma"] cmis) t.lib_ocaml; (* Declare directories dependencies, replace "include" in _tags. *) List.iter (fun (dir, include_dirs) -> Pathname.define_context dir include_dirs) t.includes; (* Declare C libraries *) List.iter (fun (lib, dir, headers) -> (* Handle C part of library *) flag ["link"; "library"; "ocaml"; "byte"; tag_libstubs lib] (S[A"-dllib"; A("-l"^(nm_libstubs lib)); A"-cclib"; A("-l"^(nm_libstubs lib))]); flag ["link"; "library"; "ocaml"; "native"; tag_libstubs lib] (S[A"-cclib"; A("-l"^(nm_libstubs lib))]); flag ["link"; "program"; "ocaml"; "byte"; tag_libstubs lib] (S[A"-dllib"; A("dll"^(nm_libstubs lib))]); (* When ocaml link something that use the C library, then one need that file to be up to date. This holds both for programs and for libraries. *) dep ["link"; "ocaml"; tag_libstubs lib] [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)]; dep ["compile"; "ocaml"; tag_libstubs lib] [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)]; (* TODO: be more specific about what depends on headers *) (* Depends on .h files *) dep ["compile"; "c"] headers; (* Setup search path for lib *) flag ["link"; "ocaml"; "use_"^lib] (S[A"-I"; P(dir)]); ) t.lib_c; (* Add flags *) List.iter (fun (tags, cond_specs) -> let spec = BaseEnvLight.var_choose cond_specs env in let rec eval_specs = function | S lst -> S (List.map eval_specs lst) | A str -> A (BaseEnvLight.var_expand str env) | spec -> spec in flag tags & (eval_specs spec)) t.flags | _ -> () let dispatch_default conf t = dispatch_combine [ dispatch t; MyOCamlbuildFindlib.dispatch conf; ] end # 606 "myocamlbuild.ml" open Ocamlbuild_plugin;; let package_default = { MyOCamlbuildBase.lib_ocaml = [("core", ["src"], []); ("core_top", ["top"], [])]; lib_c = [ ("core", "src", [ "src/includes.h"; "src/iobuf.h"; "src/jane_common.h"; "src/nanosecond_stat.h"; "src/ocaml_utils.h"; "src/ocaml_utils_macros.h"; "src/recvmmsg.h"; "src/socketaddr.h"; "src/timespec.h"; "src/unix_utils.h"; "src/core_config.h" ]) ]; flags = [ (["oasis_library_core_cclib"; "link"], [ (OASISExpr.EBool true, S []); (OASISExpr.EFlag "rt", S [A "-cclib"; A "-lrt"]) ]); (["oasis_library_core_cclib"; "ocamlmklib"; "c"], [ (OASISExpr.EBool true, S []); (OASISExpr.EFlag "rt", S [A "-lrt"]) ]) ]; includes = [("top", ["src"]); ("test", ["src"])] } ;; let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false} let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;; # 652 "myocamlbuild.ml" (* OASIS_STOP *) let dispatch = function | After_rules -> dep ["ocaml"; "ocamldep"; "mlh"] ["src/version_defaults.mlh"; "src/core_config.mlh"]; flag ["mlh"; "ocaml"; "ocamldep"] (S[A"-ppopt"; A"-Isrc/"]); flag ["mlh"; "ocaml"; "compile"] (S[A"-ppopt"; A"-Isrc/"]); flag ["mlh"; "ocaml"; "doc"] (S[A"-ppopt"; A"-Isrc/"]); flag ["c"; "compile"] & S[A"-I"; A"src"; A"-package"; A"core_kernel"]; List.iter (fun tag -> pflag ["ocaml"; tag] "pa_ounit_lib" (fun s -> S[A"-ppopt"; A"-pa-ounit-lib"; A"-ppopt"; A s])) ["ocamldep"; "compile"; "doc"] | _ -> () let () = Ocamlbuild_plugin.dispatch (fun hook -> dispatch hook; dispatch_default hook) core-113.00.00/setup.ml000066400000000000000000006007501256461075500144610ustar00rootroot00000000000000(* OASIS_START *) (* DO NOT EDIT (digest: 53e26a5542dc9ed733bdd0a4959d1886) *) (* Regenerated by OASIS v0.4.5 Visit http://oasis.forge.ocamlcore.org for more information and documentation about functions used in this file. *) module OASISGettext = struct (* # 22 "src/oasis/OASISGettext.ml" *) let ns_ str = str let s_ str = str let f_ (str: ('a, 'b, 'c, 'd) format4) = str let fn_ fmt1 fmt2 n = if n = 1 then fmt1^^"" else fmt2^^"" let init = [] end module OASISContext = struct (* # 22 "src/oasis/OASISContext.ml" *) open OASISGettext type level = [ `Debug | `Info | `Warning | `Error] type t = { (* TODO: replace this by a proplist. *) quiet: bool; info: bool; debug: bool; ignore_plugins: bool; ignore_unknown_fields: bool; printf: level -> string -> unit; } let printf lvl str = let beg = match lvl with | `Error -> s_ "E: " | `Warning -> s_ "W: " | `Info -> s_ "I: " | `Debug -> s_ "D: " in prerr_endline (beg^str) let default = ref { quiet = false; info = false; debug = false; ignore_plugins = false; ignore_unknown_fields = false; printf = printf; } let quiet = {!default with quiet = true} let fspecs () = (* TODO: don't act on default. *) let ignore_plugins = ref false in ["-quiet", Arg.Unit (fun () -> default := {!default with quiet = true}), s_ " Run quietly"; "-info", Arg.Unit (fun () -> default := {!default with info = true}), s_ " Display information message"; "-debug", Arg.Unit (fun () -> default := {!default with debug = true}), s_ " Output debug message"; "-ignore-plugins", Arg.Set ignore_plugins, s_ " Ignore plugin's field."; "-C", (* TODO: remove this chdir. *) Arg.String (fun str -> Sys.chdir str), s_ "dir Change directory before running."], fun () -> {!default with ignore_plugins = !ignore_plugins} end module OASISString = struct (* # 22 "src/oasis/OASISString.ml" *) (** Various string utilities. Mostly inspired by extlib and batteries ExtString and BatString libraries. @author Sylvain Le Gall *) let nsplitf str f = if str = "" then [] else let buf = Buffer.create 13 in let lst = ref [] in let push () = lst := Buffer.contents buf :: !lst; Buffer.clear buf in let str_len = String.length str in for i = 0 to str_len - 1 do if f str.[i] then push () else Buffer.add_char buf str.[i] done; push (); List.rev !lst (** [nsplit c s] Split the string [s] at char [c]. It doesn't include the separator. *) let nsplit str c = nsplitf str ((=) c) let find ~what ?(offset=0) str = let what_idx = ref 0 in let str_idx = ref offset in while !str_idx < String.length str && !what_idx < String.length what do if str.[!str_idx] = what.[!what_idx] then incr what_idx else what_idx := 0; incr str_idx done; if !what_idx <> String.length what then raise Not_found else !str_idx - !what_idx let sub_start str len = let str_len = String.length str in if len >= str_len then "" else String.sub str len (str_len - len) let sub_end ?(offset=0) str len = let str_len = String.length str in if len >= str_len then "" else String.sub str 0 (str_len - len) let starts_with ~what ?(offset=0) str = let what_idx = ref 0 in let str_idx = ref offset in let ok = ref true in while !ok && !str_idx < String.length str && !what_idx < String.length what do if str.[!str_idx] = what.[!what_idx] then incr what_idx else ok := false; incr str_idx done; if !what_idx = String.length what then true else false let strip_starts_with ~what str = if starts_with ~what str then sub_start str (String.length what) else raise Not_found let ends_with ~what ?(offset=0) str = let what_idx = ref ((String.length what) - 1) in let str_idx = ref ((String.length str) - 1) in let ok = ref true in while !ok && offset <= !str_idx && 0 <= !what_idx do if str.[!str_idx] = what.[!what_idx] then decr what_idx else ok := false; decr str_idx done; if !what_idx = -1 then true else false let strip_ends_with ~what str = if ends_with ~what str then sub_end str (String.length what) else raise Not_found let replace_chars f s = let buf = Buffer.create (String.length s) in String.iter (fun c -> Buffer.add_char buf (f c)) s; Buffer.contents buf end module OASISUtils = struct (* # 22 "src/oasis/OASISUtils.ml" *) open OASISGettext module MapExt = struct module type S = sig include Map.S val add_list: 'a t -> (key * 'a) list -> 'a t val of_list: (key * 'a) list -> 'a t val to_list: 'a t -> (key * 'a) list end module Make (Ord: Map.OrderedType) = struct include Map.Make(Ord) let rec add_list t = function | (k, v) :: tl -> add_list (add k v t) tl | [] -> t let of_list lst = add_list empty lst let to_list t = fold (fun k v acc -> (k, v) :: acc) t [] end end module MapString = MapExt.Make(String) module SetExt = struct module type S = sig include Set.S val add_list: t -> elt list -> t val of_list: elt list -> t val to_list: t -> elt list end module Make (Ord: Set.OrderedType) = struct include Set.Make(Ord) let rec add_list t = function | e :: tl -> add_list (add e t) tl | [] -> t let of_list lst = add_list empty lst let to_list = elements end end module SetString = SetExt.Make(String) let compare_csl s1 s2 = String.compare (String.lowercase s1) (String.lowercase s2) module HashStringCsl = Hashtbl.Make (struct type t = string let equal s1 s2 = (String.lowercase s1) = (String.lowercase s2) let hash s = Hashtbl.hash (String.lowercase s) end) module SetStringCsl = SetExt.Make (struct type t = string let compare = compare_csl end) let varname_of_string ?(hyphen='_') s = if String.length s = 0 then begin invalid_arg "varname_of_string" end else begin let buf = OASISString.replace_chars (fun c -> if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') then c else hyphen) s; in let buf = (* Start with a _ if digit *) if '0' <= s.[0] && s.[0] <= '9' then "_"^buf else buf in String.lowercase buf end let varname_concat ?(hyphen='_') p s = let what = String.make 1 hyphen in let p = try OASISString.strip_ends_with ~what p with Not_found -> p in let s = try OASISString.strip_starts_with ~what s with Not_found -> s in p^what^s let is_varname str = str = varname_of_string str let failwithf fmt = Printf.ksprintf failwith fmt end module PropList = struct (* # 22 "src/oasis/PropList.ml" *) open OASISGettext type name = string exception Not_set of name * string option exception No_printer of name exception Unknown_field of name * name let () = Printexc.register_printer (function | Not_set (nm, Some rsn) -> Some (Printf.sprintf (f_ "Field '%s' is not set: %s") nm rsn) | Not_set (nm, None) -> Some (Printf.sprintf (f_ "Field '%s' is not set") nm) | No_printer nm -> Some (Printf.sprintf (f_ "No default printer for value %s") nm) | Unknown_field (nm, schm) -> Some (Printf.sprintf (f_ "Field %s is not defined in schema %s") nm schm) | _ -> None) module Data = struct type t = (name, unit -> unit) Hashtbl.t let create () = Hashtbl.create 13 let clear t = Hashtbl.clear t (* # 78 "src/oasis/PropList.ml" *) end module Schema = struct type ('ctxt, 'extra) value = { get: Data.t -> string; set: Data.t -> ?context:'ctxt -> string -> unit; help: (unit -> string) option; extra: 'extra; } type ('ctxt, 'extra) t = { name: name; fields: (name, ('ctxt, 'extra) value) Hashtbl.t; order: name Queue.t; name_norm: string -> string; } let create ?(case_insensitive=false) nm = { name = nm; fields = Hashtbl.create 13; order = Queue.create (); name_norm = (if case_insensitive then String.lowercase else fun s -> s); } let add t nm set get extra help = let key = t.name_norm nm in if Hashtbl.mem t.fields key then failwith (Printf.sprintf (f_ "Field '%s' is already defined in schema '%s'") nm t.name); Hashtbl.add t.fields key { set = set; get = get; help = help; extra = extra; }; Queue.add nm t.order let mem t nm = Hashtbl.mem t.fields nm let find t nm = try Hashtbl.find t.fields (t.name_norm nm) with Not_found -> raise (Unknown_field (nm, t.name)) let get t data nm = (find t nm).get data let set t data nm ?context x = (find t nm).set data ?context x let fold f acc t = Queue.fold (fun acc k -> let v = find t k in f acc k v.extra v.help) acc t.order let iter f t = fold (fun () -> f) () t let name t = t.name end module Field = struct type ('ctxt, 'value, 'extra) t = { set: Data.t -> ?context:'ctxt -> 'value -> unit; get: Data.t -> 'value; sets: Data.t -> ?context:'ctxt -> string -> unit; gets: Data.t -> string; help: (unit -> string) option; extra: 'extra; } let new_id = let last_id = ref 0 in fun () -> incr last_id; !last_id let create ?schema ?name ?parse ?print ?default ?update ?help extra = (* Default value container *) let v = ref None in (* If name is not given, create unique one *) let nm = match name with | Some s -> s | None -> Printf.sprintf "_anon_%d" (new_id ()) in (* Last chance to get a value: the default *) let default () = match default with | Some d -> d | None -> raise (Not_set (nm, Some (s_ "no default value"))) in (* Get data *) let get data = (* Get value *) try (Hashtbl.find data nm) (); match !v with | Some x -> x | None -> default () with Not_found -> default () in (* Set data *) let set data ?context x = let x = match update with | Some f -> begin try f ?context (get data) x with Not_set _ -> x end | None -> x in Hashtbl.replace data nm (fun () -> v := Some x) in (* Parse string value, if possible *) let parse = match parse with | Some f -> f | None -> fun ?context s -> failwith (Printf.sprintf (f_ "Cannot parse field '%s' when setting value %S") nm s) in (* Set data, from string *) let sets data ?context s = set ?context data (parse ?context s) in (* Output value as string, if possible *) let print = match print with | Some f -> f | None -> fun _ -> raise (No_printer nm) in (* Get data, as a string *) let gets data = print (get data) in begin match schema with | Some t -> Schema.add t nm sets gets extra help | None -> () end; { set = set; get = get; sets = sets; gets = gets; help = help; extra = extra; } let fset data t ?context x = t.set data ?context x let fget data t = t.get data let fsets data t ?context s = t.sets data ?context s let fgets data t = t.gets data end module FieldRO = struct let create ?schema ?name ?parse ?print ?default ?update ?help extra = let fld = Field.create ?schema ?name ?parse ?print ?default ?update ?help extra in fun data -> Field.fget data fld end end module OASISMessage = struct (* # 22 "src/oasis/OASISMessage.ml" *) open OASISGettext open OASISContext let generic_message ~ctxt lvl fmt = let cond = if ctxt.quiet then false else match lvl with | `Debug -> ctxt.debug | `Info -> ctxt.info | _ -> true in Printf.ksprintf (fun str -> if cond then begin ctxt.printf lvl str end) fmt let debug ~ctxt fmt = generic_message ~ctxt `Debug fmt let info ~ctxt fmt = generic_message ~ctxt `Info fmt let warning ~ctxt fmt = generic_message ~ctxt `Warning fmt let error ~ctxt fmt = generic_message ~ctxt `Error fmt end module OASISVersion = struct (* # 22 "src/oasis/OASISVersion.ml" *) open OASISGettext type s = string type t = string type comparator = | VGreater of t | VGreaterEqual of t | VEqual of t | VLesser of t | VLesserEqual of t | VOr of comparator * comparator | VAnd of comparator * comparator (* Range of allowed characters *) let is_digit c = '0' <= c && c <= '9' let is_alpha c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') let is_special = function | '.' | '+' | '-' | '~' -> true | _ -> false let rec version_compare v1 v2 = if v1 <> "" || v2 <> "" then begin (* Compare ascii string, using special meaning for version * related char *) let val_ascii c = if c = '~' then -1 else if is_digit c then 0 else if c = '\000' then 0 else if is_alpha c then Char.code c else (Char.code c) + 256 in let len1 = String.length v1 in let len2 = String.length v2 in let p = ref 0 in (** Compare ascii part *) let compare_vascii () = let cmp = ref 0 in while !cmp = 0 && !p < len1 && !p < len2 && not (is_digit v1.[!p] && is_digit v2.[!p]) do cmp := (val_ascii v1.[!p]) - (val_ascii v2.[!p]); incr p done; if !cmp = 0 && !p < len1 && !p = len2 then val_ascii v1.[!p] else if !cmp = 0 && !p = len1 && !p < len2 then - (val_ascii v2.[!p]) else !cmp in (** Compare digit part *) let compare_digit () = let extract_int v p = let start_p = !p in while !p < String.length v && is_digit v.[!p] do incr p done; let substr = String.sub v !p ((String.length v) - !p) in let res = match String.sub v start_p (!p - start_p) with | "" -> 0 | s -> int_of_string s in res, substr in let i1, tl1 = extract_int v1 (ref !p) in let i2, tl2 = extract_int v2 (ref !p) in i1 - i2, tl1, tl2 in match compare_vascii () with | 0 -> begin match compare_digit () with | 0, tl1, tl2 -> if tl1 <> "" && is_digit tl1.[0] then 1 else if tl2 <> "" && is_digit tl2.[0] then -1 else version_compare tl1 tl2 | n, _, _ -> n end | n -> n end else begin 0 end let version_of_string str = str let string_of_version t = t let version_compare_string s1 s2 = version_compare (version_of_string s1) (version_of_string s2) let chop t = try let pos = String.rindex t '.' in String.sub t 0 pos with Not_found -> t let rec comparator_apply v op = match op with | VGreater cv -> (version_compare v cv) > 0 | VGreaterEqual cv -> (version_compare v cv) >= 0 | VLesser cv -> (version_compare v cv) < 0 | VLesserEqual cv -> (version_compare v cv) <= 0 | VEqual cv -> (version_compare v cv) = 0 | VOr (op1, op2) -> (comparator_apply v op1) || (comparator_apply v op2) | VAnd (op1, op2) -> (comparator_apply v op1) && (comparator_apply v op2) let rec string_of_comparator = function | VGreater v -> "> "^(string_of_version v) | VEqual v -> "= "^(string_of_version v) | VLesser v -> "< "^(string_of_version v) | VGreaterEqual v -> ">= "^(string_of_version v) | VLesserEqual v -> "<= "^(string_of_version v) | VOr (c1, c2) -> (string_of_comparator c1)^" || "^(string_of_comparator c2) | VAnd (c1, c2) -> (string_of_comparator c1)^" && "^(string_of_comparator c2) let rec varname_of_comparator = let concat p v = OASISUtils.varname_concat p (OASISUtils.varname_of_string (string_of_version v)) in function | VGreater v -> concat "gt" v | VLesser v -> concat "lt" v | VEqual v -> concat "eq" v | VGreaterEqual v -> concat "ge" v | VLesserEqual v -> concat "le" v | VOr (c1, c2) -> (varname_of_comparator c1)^"_or_"^(varname_of_comparator c2) | VAnd (c1, c2) -> (varname_of_comparator c1)^"_and_"^(varname_of_comparator c2) let rec comparator_ge v' = let cmp v = version_compare v v' >= 0 in function | VEqual v | VGreaterEqual v | VGreater v -> cmp v | VLesserEqual _ | VLesser _ -> false | VOr (c1, c2) -> comparator_ge v' c1 || comparator_ge v' c2 | VAnd (c1, c2) -> comparator_ge v' c1 && comparator_ge v' c2 end module OASISLicense = struct (* # 22 "src/oasis/OASISLicense.ml" *) (** License for _oasis fields @author Sylvain Le Gall *) type license = string type license_exception = string type license_version = | Version of OASISVersion.t | VersionOrLater of OASISVersion.t | NoVersion type license_dep_5_unit = { license: license; excption: license_exception option; version: license_version; } type license_dep_5 = | DEP5Unit of license_dep_5_unit | DEP5Or of license_dep_5 list | DEP5And of license_dep_5 list type t = | DEP5License of license_dep_5 | OtherLicense of string (* URL *) end module OASISExpr = struct (* # 22 "src/oasis/OASISExpr.ml" *) open OASISGettext type test = string type flag = string type t = | EBool of bool | ENot of t | EAnd of t * t | EOr of t * t | EFlag of flag | ETest of test * string type 'a choices = (t * 'a) list let eval var_get t = let rec eval' = function | EBool b -> b | ENot e -> not (eval' e) | EAnd (e1, e2) -> (eval' e1) && (eval' e2) | EOr (e1, e2) -> (eval' e1) || (eval' e2) | EFlag nm -> let v = var_get nm in assert(v = "true" || v = "false"); (v = "true") | ETest (nm, vl) -> let v = var_get nm in (v = vl) in eval' t let choose ?printer ?name var_get lst = let rec choose_aux = function | (cond, vl) :: tl -> if eval var_get cond then vl else choose_aux tl | [] -> let str_lst = if lst = [] then s_ "" else String.concat (s_ ", ") (List.map (fun (cond, vl) -> match printer with | Some p -> p vl | None -> s_ "") lst) in match name with | Some nm -> failwith (Printf.sprintf (f_ "No result for the choice list '%s': %s") nm str_lst) | None -> failwith (Printf.sprintf (f_ "No result for a choice list: %s") str_lst) in choose_aux (List.rev lst) end module OASISText = struct (* # 22 "src/oasis/OASISText.ml" *) type elt = | Para of string | Verbatim of string | BlankLine type t = elt list end module OASISTypes = struct (* # 22 "src/oasis/OASISTypes.ml" *) type name = string type package_name = string type url = string type unix_dirname = string type unix_filename = string type host_dirname = string type host_filename = string type prog = string type arg = string type args = string list type command_line = (prog * arg list) type findlib_name = string type findlib_full = string type compiled_object = | Byte | Native | Best type dependency = | FindlibPackage of findlib_full * OASISVersion.comparator option | InternalLibrary of name type tool = | ExternalTool of name | InternalExecutable of name type vcs = | Darcs | Git | Svn | Cvs | Hg | Bzr | Arch | Monotone | OtherVCS of url type plugin_kind = [ `Configure | `Build | `Doc | `Test | `Install | `Extra ] type plugin_data_purpose = [ `Configure | `Build | `Install | `Clean | `Distclean | `Install | `Uninstall | `Test | `Doc | `Extra | `Other of string ] type 'a plugin = 'a * name * OASISVersion.t option type all_plugin = plugin_kind plugin type plugin_data = (all_plugin * plugin_data_purpose * (unit -> unit)) list (* # 115 "src/oasis/OASISTypes.ml" *) type 'a conditional = 'a OASISExpr.choices type custom = { pre_command: (command_line option) conditional; post_command: (command_line option) conditional; } type common_section = { cs_name: name; cs_data: PropList.Data.t; cs_plugin_data: plugin_data; } type build_section = { bs_build: bool conditional; bs_install: bool conditional; bs_path: unix_dirname; bs_compiled_object: compiled_object; bs_build_depends: dependency list; bs_build_tools: tool list; bs_c_sources: unix_filename list; bs_data_files: (unix_filename * unix_filename option) list; bs_ccopt: args conditional; bs_cclib: args conditional; bs_dlllib: args conditional; bs_dllpath: args conditional; bs_byteopt: args conditional; bs_nativeopt: args conditional; } type library = { lib_modules: string list; lib_pack: bool; lib_internal_modules: string list; lib_findlib_parent: findlib_name option; lib_findlib_name: findlib_name option; lib_findlib_containers: findlib_name list; } type object_ = { obj_modules: string list; obj_findlib_fullname: findlib_name list option; } type executable = { exec_custom: bool; exec_main_is: unix_filename; } type flag = { flag_description: string option; flag_default: bool conditional; } type source_repository = { src_repo_type: vcs; src_repo_location: url; src_repo_browser: url option; src_repo_module: string option; src_repo_branch: string option; src_repo_tag: string option; src_repo_subdir: unix_filename option; } type test = { test_type: [`Test] plugin; test_command: command_line conditional; test_custom: custom; test_working_directory: unix_filename option; test_run: bool conditional; test_tools: tool list; } type doc_format = | HTML of unix_filename | DocText | PDF | PostScript | Info of unix_filename | DVI | OtherDoc type doc = { doc_type: [`Doc] plugin; doc_custom: custom; doc_build: bool conditional; doc_install: bool conditional; doc_install_dir: unix_filename; doc_title: string; doc_authors: string list; doc_abstract: string option; doc_format: doc_format; doc_data_files: (unix_filename * unix_filename option) list; doc_build_tools: tool list; } type section = | Library of common_section * build_section * library | Object of common_section * build_section * object_ | Executable of common_section * build_section * executable | Flag of common_section * flag | SrcRepo of common_section * source_repository | Test of common_section * test | Doc of common_section * doc type section_kind = [ `Library | `Object | `Executable | `Flag | `SrcRepo | `Test | `Doc ] type package = { oasis_version: OASISVersion.t; ocaml_version: OASISVersion.comparator option; findlib_version: OASISVersion.comparator option; alpha_features: string list; beta_features: string list; name: package_name; version: OASISVersion.t; license: OASISLicense.t; license_file: unix_filename option; copyrights: string list; maintainers: string list; authors: string list; homepage: url option; synopsis: string; description: OASISText.t option; categories: url list; conf_type: [`Configure] plugin; conf_custom: custom; build_type: [`Build] plugin; build_custom: custom; install_type: [`Install] plugin; install_custom: custom; uninstall_custom: custom; clean_custom: custom; distclean_custom: custom; files_ab: unix_filename list; sections: section list; plugins: [`Extra] plugin list; disable_oasis_section: unix_filename list; schema_data: PropList.Data.t; plugin_data: plugin_data; } end module OASISFeatures = struct (* # 22 "src/oasis/OASISFeatures.ml" *) open OASISTypes open OASISUtils open OASISGettext open OASISVersion module MapPlugin = Map.Make (struct type t = plugin_kind * name let compare = Pervasives.compare end) module Data = struct type t = { oasis_version: OASISVersion.t; plugin_versions: OASISVersion.t option MapPlugin.t; alpha_features: string list; beta_features: string list; } let create oasis_version alpha_features beta_features = { oasis_version = oasis_version; plugin_versions = MapPlugin.empty; alpha_features = alpha_features; beta_features = beta_features } let of_package pkg = create pkg.OASISTypes.oasis_version pkg.OASISTypes.alpha_features pkg.OASISTypes.beta_features let add_plugin (plugin_kind, plugin_name, plugin_version) t = {t with plugin_versions = MapPlugin.add (plugin_kind, plugin_name) plugin_version t.plugin_versions} let plugin_version plugin_kind plugin_name t = MapPlugin.find (plugin_kind, plugin_name) t.plugin_versions let to_string t = Printf.sprintf "oasis_version: %s; alpha_features: %s; beta_features: %s; \ plugins_version: %s" (OASISVersion.string_of_version t.oasis_version) (String.concat ", " t.alpha_features) (String.concat ", " t.beta_features) (String.concat ", " (MapPlugin.fold (fun (_, plg) ver_opt acc -> (plg^ (match ver_opt with | Some v -> " "^(OASISVersion.string_of_version v) | None -> "")) :: acc) t.plugin_versions [])) end type origin = | Field of string * string | Section of string | NoOrigin type stage = Alpha | Beta let string_of_stage = function | Alpha -> "alpha" | Beta -> "beta" let field_of_stage = function | Alpha -> "AlphaFeatures" | Beta -> "BetaFeatures" type publication = InDev of stage | SinceVersion of OASISVersion.t type t = { name: string; plugin: all_plugin option; publication: publication; description: unit -> string; } (* TODO: mutex protect this. *) let all_features = Hashtbl.create 13 let since_version ver_str = SinceVersion (version_of_string ver_str) let alpha = InDev Alpha let beta = InDev Beta let to_string t = Printf.sprintf "feature: %s; plugin: %s; publication: %s" t.name (match t.plugin with | None -> "" | Some (_, nm, _) -> nm) (match t.publication with | InDev stage -> string_of_stage stage | SinceVersion ver -> ">= "^(OASISVersion.string_of_version ver)) let data_check t data origin = let no_message = "no message" in let check_feature features stage = let has_feature = List.mem t.name features in if not has_feature then match origin with | Field (fld, where) -> Some (Printf.sprintf (f_ "Field %s in %s is only available when feature %s \ is in field %s.") fld where t.name (field_of_stage stage)) | Section sct -> Some (Printf.sprintf (f_ "Section %s is only available when features %s \ is in field %s.") sct t.name (field_of_stage stage)) | NoOrigin -> Some no_message else None in let version_is_good ~min_version version fmt = let version_is_good = OASISVersion.comparator_apply version (OASISVersion.VGreaterEqual min_version) in Printf.ksprintf (fun str -> if version_is_good then None else Some str) fmt in match origin, t.plugin, t.publication with | _, _, InDev Alpha -> check_feature data.Data.alpha_features Alpha | _, _, InDev Beta -> check_feature data.Data.beta_features Beta | Field(fld, where), None, SinceVersion min_version -> version_is_good ~min_version data.Data.oasis_version (f_ "Field %s in %s is only valid since OASIS v%s, update \ OASISFormat field from '%s' to '%s' after checking \ OASIS changelog.") fld where (string_of_version min_version) (string_of_version data.Data.oasis_version) (string_of_version min_version) | Field(fld, where), Some(plugin_knd, plugin_name, _), SinceVersion min_version -> begin try let plugin_version_current = try match Data.plugin_version plugin_knd plugin_name data with | Some ver -> ver | None -> failwithf (f_ "Field %s in %s is only valid for the OASIS \ plugin %s since v%s, but no plugin version is \ defined in the _oasis file, change '%s' to \ '%s (%s)' in your _oasis file.") fld where plugin_name (string_of_version min_version) plugin_name plugin_name (string_of_version min_version) with Not_found -> failwithf (f_ "Field %s in %s is only valid when the OASIS plugin %s \ is defined.") fld where plugin_name in version_is_good ~min_version plugin_version_current (f_ "Field %s in %s is only valid for the OASIS plugin %s \ since v%s, update your plugin from '%s (%s)' to \ '%s (%s)' after checking the plugin's changelog.") fld where plugin_name (string_of_version min_version) plugin_name (string_of_version plugin_version_current) plugin_name (string_of_version min_version) with Failure msg -> Some msg end | Section sct, None, SinceVersion min_version -> version_is_good ~min_version data.Data.oasis_version (f_ "Section %s is only valid for since OASIS v%s, update \ OASISFormat field from '%s' to '%s' after checking OASIS \ changelog.") sct (string_of_version min_version) (string_of_version data.Data.oasis_version) (string_of_version min_version) | Section sct, Some(plugin_knd, plugin_name, _), SinceVersion min_version -> begin try let plugin_version_current = try match Data.plugin_version plugin_knd plugin_name data with | Some ver -> ver | None -> failwithf (f_ "Section %s is only valid for the OASIS \ plugin %s since v%s, but no plugin version is \ defined in the _oasis file, change '%s' to \ '%s (%s)' in your _oasis file.") sct plugin_name (string_of_version min_version) plugin_name plugin_name (string_of_version min_version) with Not_found -> failwithf (f_ "Section %s is only valid when the OASIS plugin %s \ is defined.") sct plugin_name in version_is_good ~min_version plugin_version_current (f_ "Section %s is only valid for the OASIS plugin %s \ since v%s, update your plugin from '%s (%s)' to \ '%s (%s)' after checking the plugin's changelog.") sct plugin_name (string_of_version min_version) plugin_name (string_of_version plugin_version_current) plugin_name (string_of_version min_version) with Failure msg -> Some msg end | NoOrigin, None, SinceVersion min_version -> version_is_good ~min_version data.Data.oasis_version "%s" no_message | NoOrigin, Some(plugin_knd, plugin_name, _), SinceVersion min_version -> begin try let plugin_version_current = match Data.plugin_version plugin_knd plugin_name data with | Some ver -> ver | None -> raise Not_found in version_is_good ~min_version plugin_version_current "%s" no_message with Not_found -> Some no_message end let data_assert t data origin = match data_check t data origin with | None -> () | Some str -> failwith str let data_test t data = match data_check t data NoOrigin with | None -> true | Some str -> false let package_test t pkg = data_test t (Data.of_package pkg) let create ?plugin name publication description = let () = if Hashtbl.mem all_features name then failwithf "Feature '%s' is already declared." name in let t = { name = name; plugin = plugin; publication = publication; description = description; } in Hashtbl.add all_features name t; t let get_stage name = try (Hashtbl.find all_features name).publication with Not_found -> failwithf (f_ "Feature %s doesn't exist.") name let list () = Hashtbl.fold (fun _ v acc -> v :: acc) all_features [] (* * Real flags. *) let features = create "features_fields" (since_version "0.4") (fun () -> s_ "Enable to experiment not yet official features.") let flag_docs = create "flag_docs" (since_version "0.3") (fun () -> s_ "Building docs require '-docs' flag at configure.") let flag_tests = create "flag_tests" (since_version "0.3") (fun () -> s_ "Running tests require '-tests' flag at configure.") let pack = create "pack" (since_version "0.3") (fun () -> s_ "Allow to create packed library.") let section_object = create "section_object" beta (fun () -> s_ "Implement an object section.") let dynrun_for_release = create "dynrun_for_release" alpha (fun () -> s_ "Make '-setup-update dynamic' suitable for releasing project.") let compiled_setup_ml = create "compiled_setup_ml" alpha (fun () -> s_ "It compiles the setup.ml and speed-up actions done with it.") let disable_oasis_section = create "disable_oasis_section" alpha (fun () -> s_ "Allows the OASIS section comments and digest to be omitted in \ generated files.") let no_automatic_syntax = create "no_automatic_syntax" alpha (fun () -> s_ "Disable the automatic inclusion of -syntax camlp4o for packages \ that matches the internal heuristic (if a dependency ends with \ a .syntax or is a well known syntax).") end module OASISUnixPath = struct (* # 22 "src/oasis/OASISUnixPath.ml" *) type unix_filename = string type unix_dirname = string type host_filename = string type host_dirname = string let current_dir_name = "." let parent_dir_name = ".." let is_current_dir fn = fn = current_dir_name || fn = "" let concat f1 f2 = if is_current_dir f1 then f2 else let f1' = try OASISString.strip_ends_with ~what:"/" f1 with Not_found -> f1 in f1'^"/"^f2 let make = function | hd :: tl -> List.fold_left (fun f p -> concat f p) hd tl | [] -> invalid_arg "OASISUnixPath.make" let dirname f = try String.sub f 0 (String.rindex f '/') with Not_found -> current_dir_name let basename f = try let pos_start = (String.rindex f '/') + 1 in String.sub f pos_start ((String.length f) - pos_start) with Not_found -> f let chop_extension f = try let last_dot = String.rindex f '.' in let sub = String.sub f 0 last_dot in try let last_slash = String.rindex f '/' in if last_slash < last_dot then sub else f with Not_found -> sub with Not_found -> f let capitalize_file f = let dir = dirname f in let base = basename f in concat dir (String.capitalize base) let uncapitalize_file f = let dir = dirname f in let base = basename f in concat dir (String.uncapitalize base) end module OASISHostPath = struct (* # 22 "src/oasis/OASISHostPath.ml" *) open Filename module Unix = OASISUnixPath let make = function | [] -> invalid_arg "OASISHostPath.make" | hd :: tl -> List.fold_left Filename.concat hd tl let of_unix ufn = if Sys.os_type = "Unix" then ufn else make (List.map (fun p -> if p = Unix.current_dir_name then current_dir_name else if p = Unix.parent_dir_name then parent_dir_name else p) (OASISString.nsplit ufn '/')) end module OASISSection = struct (* # 22 "src/oasis/OASISSection.ml" *) open OASISTypes let section_kind_common = function | Library (cs, _, _) -> `Library, cs | Object (cs, _, _) -> `Object, cs | Executable (cs, _, _) -> `Executable, cs | Flag (cs, _) -> `Flag, cs | SrcRepo (cs, _) -> `SrcRepo, cs | Test (cs, _) -> `Test, cs | Doc (cs, _) -> `Doc, cs let section_common sct = snd (section_kind_common sct) let section_common_set cs = function | Library (_, bs, lib) -> Library (cs, bs, lib) | Object (_, bs, obj) -> Object (cs, bs, obj) | Executable (_, bs, exec) -> Executable (cs, bs, exec) | Flag (_, flg) -> Flag (cs, flg) | SrcRepo (_, src_repo) -> SrcRepo (cs, src_repo) | Test (_, tst) -> Test (cs, tst) | Doc (_, doc) -> Doc (cs, doc) (** Key used to identify section *) let section_id sct = let k, cs = section_kind_common sct in k, cs.cs_name let string_of_section sct = let k, nm = section_id sct in (match k with | `Library -> "library" | `Object -> "object" | `Executable -> "executable" | `Flag -> "flag" | `SrcRepo -> "src repository" | `Test -> "test" | `Doc -> "doc") ^" "^nm let section_find id scts = List.find (fun sct -> id = section_id sct) scts module CSection = struct type t = section let id = section_id let compare t1 t2 = compare (id t1) (id t2) let equal t1 t2 = (id t1) = (id t2) let hash t = Hashtbl.hash (id t) end module MapSection = Map.Make(CSection) module SetSection = Set.Make(CSection) end module OASISBuildSection = struct (* # 22 "src/oasis/OASISBuildSection.ml" *) end module OASISExecutable = struct (* # 22 "src/oasis/OASISExecutable.ml" *) open OASISTypes let unix_exec_is (cs, bs, exec) is_native ext_dll suffix_program = let dir = OASISUnixPath.concat bs.bs_path (OASISUnixPath.dirname exec.exec_main_is) in let is_native_exec = match bs.bs_compiled_object with | Native -> true | Best -> is_native () | Byte -> false in OASISUnixPath.concat dir (cs.cs_name^(suffix_program ())), if not is_native_exec && not exec.exec_custom && bs.bs_c_sources <> [] then Some (dir^"/dll"^cs.cs_name^"_stubs"^(ext_dll ())) else None end module OASISLibrary = struct (* # 22 "src/oasis/OASISLibrary.ml" *) open OASISTypes open OASISUtils open OASISGettext open OASISSection (* Look for a module file, considering capitalization or not. *) let find_module source_file_exists bs modul = let possible_base_fn = List.map (OASISUnixPath.concat bs.bs_path) [modul; OASISUnixPath.uncapitalize_file modul; OASISUnixPath.capitalize_file modul] in (* TODO: we should be able to be able to determine the source for every * files. Hence we should introduce a Module(source: fn) for the fields * Modules and InternalModules *) List.fold_left (fun acc base_fn -> match acc with | `No_sources _ -> begin let file_found = List.fold_left (fun acc ext -> if source_file_exists (base_fn^ext) then (base_fn^ext) :: acc else acc) [] [".ml"; ".mli"; ".mll"; ".mly"] in match file_found with | [] -> acc | lst -> `Sources (base_fn, lst) end | `Sources _ -> acc) (`No_sources possible_base_fn) possible_base_fn let source_unix_files ~ctxt (cs, bs, lib) source_file_exists = List.fold_left (fun acc modul -> match find_module source_file_exists bs modul with | `Sources (base_fn, lst) -> (base_fn, lst) :: acc | `No_sources _ -> OASISMessage.warning ~ctxt (f_ "Cannot find source file matching \ module '%s' in library %s") modul cs.cs_name; acc) [] (lib.lib_modules @ lib.lib_internal_modules) let generated_unix_files ~ctxt ~is_native ~has_native_dynlink ~ext_lib ~ext_dll ~source_file_exists (cs, bs, lib) = let find_modules lst ext = let find_module modul = match find_module source_file_exists bs modul with | `Sources (base_fn, [fn]) when ext <> "cmi" && Filename.check_suffix fn ".mli" -> None (* No implementation files for pure interface. *) | `Sources (base_fn, _) -> Some [base_fn] | `No_sources lst -> OASISMessage.warning ~ctxt (f_ "Cannot find source file matching \ module '%s' in library %s") modul cs.cs_name; Some lst in List.fold_left (fun acc nm -> match find_module nm with | None -> acc | Some base_fns -> List.map (fun base_fn -> base_fn ^"."^ext) base_fns :: acc) [] lst in (* The .cmx that be compiled along *) let cmxs = let should_be_built = match bs.bs_compiled_object with | Native -> true | Best -> is_native | Byte -> false in if should_be_built then if lib.lib_pack then find_modules [cs.cs_name] "cmx" else find_modules (lib.lib_modules @ lib.lib_internal_modules) "cmx" else [] in let acc_nopath = [] in (* The headers and annot/cmt files that should be compiled along *) let headers = let sufx = if lib.lib_pack then [".cmti"; ".cmt"; ".annot"] else [".cmi"; ".cmti"; ".cmt"; ".annot"] in List.map begin List.fold_left begin fun accu s -> let dot = String.rindex s '.' in let base = String.sub s 0 dot in List.map ((^) base) sufx @ accu end [] end (find_modules lib.lib_modules "cmi") in (* Compute what libraries should be built *) let acc_nopath = (* Add the packed header file if required *) let add_pack_header acc = if lib.lib_pack then [cs.cs_name^".cmi"; cs.cs_name^".cmti"; cs.cs_name^".cmt"] :: acc else acc in let byte acc = add_pack_header ([cs.cs_name^".cma"] :: acc) in let native acc = let acc = add_pack_header (if has_native_dynlink then [cs.cs_name^".cmxs"] :: acc else acc) in [cs.cs_name^".cmxa"] :: [cs.cs_name^ext_lib] :: acc in match bs.bs_compiled_object with | Native -> byte (native acc_nopath) | Best when is_native -> byte (native acc_nopath) | Byte | Best -> byte acc_nopath in (* Add C library to be built *) let acc_nopath = if bs.bs_c_sources <> [] then begin ["lib"^cs.cs_name^"_stubs"^ext_lib] :: ["dll"^cs.cs_name^"_stubs"^ext_dll] :: acc_nopath end else acc_nopath in (* All the files generated *) List.rev_append (List.rev_map (List.rev_map (OASISUnixPath.concat bs.bs_path)) acc_nopath) (headers @ cmxs) end module OASISObject = struct (* # 22 "src/oasis/OASISObject.ml" *) open OASISTypes open OASISGettext let source_unix_files ~ctxt (cs, bs, obj) source_file_exists = List.fold_left (fun acc modul -> match OASISLibrary.find_module source_file_exists bs modul with | `Sources (base_fn, lst) -> (base_fn, lst) :: acc | `No_sources _ -> OASISMessage.warning ~ctxt (f_ "Cannot find source file matching \ module '%s' in object %s") modul cs.cs_name; acc) [] obj.obj_modules let generated_unix_files ~ctxt ~is_native ~source_file_exists (cs, bs, obj) = let find_module ext modul = match OASISLibrary.find_module source_file_exists bs modul with | `Sources (base_fn, _) -> [base_fn ^ ext] | `No_sources lst -> OASISMessage.warning ~ctxt (f_ "Cannot find source file matching \ module '%s' in object %s") modul cs.cs_name ; lst in let header, byte, native, c_object, f = match obj.obj_modules with | [ m ] -> (find_module ".cmi" m, find_module ".cmo" m, find_module ".cmx" m, find_module ".o" m, fun x -> x) | _ -> ([cs.cs_name ^ ".cmi"], [cs.cs_name ^ ".cmo"], [cs.cs_name ^ ".cmx"], [cs.cs_name ^ ".o"], OASISUnixPath.concat bs.bs_path) in List.map (List.map f) ( match bs.bs_compiled_object with | Native -> native :: c_object :: byte :: header :: [] | Best when is_native -> native :: c_object :: byte :: header :: [] | Byte | Best -> byte :: header :: []) end module OASISFindlib = struct (* # 22 "src/oasis/OASISFindlib.ml" *) open OASISTypes open OASISUtils open OASISGettext open OASISSection type library_name = name type findlib_part_name = name type 'a map_of_findlib_part_name = 'a OASISUtils.MapString.t exception InternalLibraryNotFound of library_name exception FindlibPackageNotFound of findlib_name type group_t = | Container of findlib_name * group_t list | Package of (findlib_name * common_section * build_section * [`Library of library | `Object of object_] * group_t list) type data = common_section * build_section * [`Library of library | `Object of object_] type tree = | Node of (data option) * (tree MapString.t) | Leaf of data let findlib_mapping pkg = (* Map from library name to either full findlib name or parts + parent. *) let fndlb_parts_of_lib_name = let fndlb_parts cs lib = let name = match lib.lib_findlib_name with | Some nm -> nm | None -> cs.cs_name in let name = String.concat "." (lib.lib_findlib_containers @ [name]) in name in List.fold_left (fun mp -> function | Library (cs, _, lib) -> begin let lib_name = cs.cs_name in let fndlb_parts = fndlb_parts cs lib in if MapString.mem lib_name mp then failwithf (f_ "The library name '%s' is used more than once.") lib_name; match lib.lib_findlib_parent with | Some lib_name_parent -> MapString.add lib_name (`Unsolved (lib_name_parent, fndlb_parts)) mp | None -> MapString.add lib_name (`Solved fndlb_parts) mp end | Object (cs, _, obj) -> begin let obj_name = cs.cs_name in if MapString.mem obj_name mp then failwithf (f_ "The object name '%s' is used more than once.") obj_name; let findlib_full_name = match obj.obj_findlib_fullname with | Some ns -> String.concat "." ns | None -> obj_name in MapString.add obj_name (`Solved findlib_full_name) mp end | Executable _ | Test _ | Flag _ | SrcRepo _ | Doc _ -> mp) MapString.empty pkg.sections in (* Solve the above graph to be only library name to full findlib name. *) let fndlb_name_of_lib_name = let rec solve visited mp lib_name lib_name_child = if SetString.mem lib_name visited then failwithf (f_ "Library '%s' is involved in a cycle \ with regard to findlib naming.") lib_name; let visited = SetString.add lib_name visited in try match MapString.find lib_name mp with | `Solved fndlb_nm -> fndlb_nm, mp | `Unsolved (lib_nm_parent, post_fndlb_nm) -> let pre_fndlb_nm, mp = solve visited mp lib_nm_parent lib_name in let fndlb_nm = pre_fndlb_nm^"."^post_fndlb_nm in fndlb_nm, MapString.add lib_name (`Solved fndlb_nm) mp with Not_found -> failwithf (f_ "Library '%s', which is defined as the findlib parent of \ library '%s', doesn't exist.") lib_name lib_name_child in let mp = MapString.fold (fun lib_name status mp -> match status with | `Solved _ -> (* Solved initialy, no need to go further *) mp | `Unsolved _ -> let _, mp = solve SetString.empty mp lib_name "" in mp) fndlb_parts_of_lib_name fndlb_parts_of_lib_name in MapString.map (function | `Solved fndlb_nm -> fndlb_nm | `Unsolved _ -> assert false) mp in (* Convert an internal library name to a findlib name. *) let findlib_name_of_library_name lib_nm = try MapString.find lib_nm fndlb_name_of_lib_name with Not_found -> raise (InternalLibraryNotFound lib_nm) in (* Add a library to the tree. *) let add sct mp = let fndlb_fullname = let cs, _, _ = sct in let lib_name = cs.cs_name in findlib_name_of_library_name lib_name in let rec add_children nm_lst (children: tree MapString.t) = match nm_lst with | (hd :: tl) -> begin let node = try add_node tl (MapString.find hd children) with Not_found -> (* New node *) new_node tl in MapString.add hd node children end | [] -> (* Should not have a nameless library. *) assert false and add_node tl node = if tl = [] then begin match node with | Node (None, children) -> Node (Some sct, children) | Leaf (cs', _, _) | Node (Some (cs', _, _), _) -> (* TODO: allow to merge Package, i.e. * archive(byte) = "foo.cma foo_init.cmo" *) let cs, _, _ = sct in failwithf (f_ "Library '%s' and '%s' have the same findlib name '%s'") cs.cs_name cs'.cs_name fndlb_fullname end else begin match node with | Leaf data -> Node (Some data, add_children tl MapString.empty) | Node (data_opt, children) -> Node (data_opt, add_children tl children) end and new_node = function | [] -> Leaf sct | hd :: tl -> Node (None, MapString.add hd (new_node tl) MapString.empty) in add_children (OASISString.nsplit fndlb_fullname '.') mp in let rec group_of_tree mp = MapString.fold (fun nm node acc -> let cur = match node with | Node (Some (cs, bs, lib), children) -> Package (nm, cs, bs, lib, group_of_tree children) | Node (None, children) -> Container (nm, group_of_tree children) | Leaf (cs, bs, lib) -> Package (nm, cs, bs, lib, []) in cur :: acc) mp [] in let group_mp = List.fold_left (fun mp -> function | Library (cs, bs, lib) -> add (cs, bs, `Library lib) mp | Object (cs, bs, obj) -> add (cs, bs, `Object obj) mp | _ -> mp) MapString.empty pkg.sections in let groups = group_of_tree group_mp in let library_name_of_findlib_name = lazy begin (* Revert findlib_name_of_library_name. *) MapString.fold (fun k v mp -> MapString.add v k mp) fndlb_name_of_lib_name MapString.empty end in let library_name_of_findlib_name fndlb_nm = try MapString.find fndlb_nm (Lazy.force library_name_of_findlib_name) with Not_found -> raise (FindlibPackageNotFound fndlb_nm) in groups, findlib_name_of_library_name, library_name_of_findlib_name let findlib_of_group = function | Container (fndlb_nm, _) | Package (fndlb_nm, _, _, _, _) -> fndlb_nm let root_of_group grp = let rec root_lib_aux = (* We do a DFS in the group. *) function | Container (_, children) -> List.fold_left (fun res grp -> if res = None then root_lib_aux grp else res) None children | Package (_, cs, bs, lib, _) -> Some (cs, bs, lib) in match root_lib_aux grp with | Some res -> res | None -> failwithf (f_ "Unable to determine root library of findlib library '%s'") (findlib_of_group grp) end module OASISFlag = struct (* # 22 "src/oasis/OASISFlag.ml" *) end module OASISPackage = struct (* # 22 "src/oasis/OASISPackage.ml" *) end module OASISSourceRepository = struct (* # 22 "src/oasis/OASISSourceRepository.ml" *) end module OASISTest = struct (* # 22 "src/oasis/OASISTest.ml" *) end module OASISDocument = struct (* # 22 "src/oasis/OASISDocument.ml" *) end module OASISExec = struct (* # 22 "src/oasis/OASISExec.ml" *) open OASISGettext open OASISUtils open OASISMessage (* TODO: I don't like this quote, it is there because $(rm) foo expands to * 'rm -f' foo... *) let run ~ctxt ?f_exit_code ?(quote=true) cmd args = let cmd = if quote then if Sys.os_type = "Win32" then if String.contains cmd ' ' then (* Double the 1st double quote... win32... sigh *) "\""^(Filename.quote cmd) else cmd else Filename.quote cmd else cmd in let cmdline = String.concat " " (cmd :: args) in info ~ctxt (f_ "Running command '%s'") cmdline; match f_exit_code, Sys.command cmdline with | None, 0 -> () | None, i -> failwithf (f_ "Command '%s' terminated with error code %d") cmdline i | Some f, i -> f i let run_read_output ~ctxt ?f_exit_code cmd args = let fn = Filename.temp_file "oasis-" ".txt" in try begin let () = run ~ctxt ?f_exit_code cmd (args @ [">"; Filename.quote fn]) in let chn = open_in fn in let routput = ref [] in begin try while true do routput := (input_line chn) :: !routput done with End_of_file -> () end; close_in chn; Sys.remove fn; List.rev !routput end with e -> (try Sys.remove fn with _ -> ()); raise e let run_read_one_line ~ctxt ?f_exit_code cmd args = match run_read_output ~ctxt ?f_exit_code cmd args with | [fst] -> fst | lst -> failwithf (f_ "Command return unexpected output %S") (String.concat "\n" lst) end module OASISFileUtil = struct (* # 22 "src/oasis/OASISFileUtil.ml" *) open OASISGettext let file_exists_case fn = let dirname = Filename.dirname fn in let basename = Filename.basename fn in if Sys.file_exists dirname then if basename = Filename.current_dir_name then true else List.mem basename (Array.to_list (Sys.readdir dirname)) else false let find_file ?(case_sensitive=true) paths exts = (* Cardinal product of two list *) let ( * ) lst1 lst2 = List.flatten (List.map (fun a -> List.map (fun b -> a, b) lst2) lst1) in let rec combined_paths lst = match lst with | p1 :: p2 :: tl -> let acc = (List.map (fun (a, b) -> Filename.concat a b) (p1 * p2)) in combined_paths (acc :: tl) | [e] -> e | [] -> [] in let alternatives = List.map (fun (p, e) -> if String.length e > 0 && e.[0] <> '.' then p ^ "." ^ e else p ^ e) ((combined_paths paths) * exts) in List.find (fun file -> (if case_sensitive then file_exists_case file else Sys.file_exists file) && not (Sys.is_directory file) ) alternatives let which ~ctxt prg = let path_sep = match Sys.os_type with | "Win32" -> ';' | _ -> ':' in let path_lst = OASISString.nsplit (Sys.getenv "PATH") path_sep in let exec_ext = match Sys.os_type with | "Win32" -> "" :: (OASISString.nsplit (Sys.getenv "PATHEXT") path_sep) | _ -> [""] in find_file ~case_sensitive:false [path_lst; [prg]] exec_ext (**/**) let rec fix_dir dn = (* Windows hack because Sys.file_exists "src\\" = false when * Sys.file_exists "src" = true *) let ln = String.length dn in if Sys.os_type = "Win32" && ln > 0 && dn.[ln - 1] = '\\' then fix_dir (String.sub dn 0 (ln - 1)) else dn let q = Filename.quote (**/**) let cp ~ctxt ?(recurse=false) src tgt = if recurse then match Sys.os_type with | "Win32" -> OASISExec.run ~ctxt "xcopy" [q src; q tgt; "/E"] | _ -> OASISExec.run ~ctxt "cp" ["-r"; q src; q tgt] else OASISExec.run ~ctxt (match Sys.os_type with | "Win32" -> "copy" | _ -> "cp") [q src; q tgt] let mkdir ~ctxt tgt = OASISExec.run ~ctxt (match Sys.os_type with | "Win32" -> "md" | _ -> "mkdir") [q tgt] let rec mkdir_parent ~ctxt f tgt = let tgt = fix_dir tgt in if Sys.file_exists tgt then begin if not (Sys.is_directory tgt) then OASISUtils.failwithf (f_ "Cannot create directory '%s', a file of the same name already \ exists") tgt end else begin mkdir_parent ~ctxt f (Filename.dirname tgt); if not (Sys.file_exists tgt) then begin f tgt; mkdir ~ctxt tgt end end let rmdir ~ctxt tgt = if Sys.readdir tgt = [||] then begin match Sys.os_type with | "Win32" -> OASISExec.run ~ctxt "rd" [q tgt] | _ -> OASISExec.run ~ctxt "rm" ["-r"; q tgt] end else begin OASISMessage.error ~ctxt (f_ "Cannot remove directory '%s': not empty.") tgt end let glob ~ctxt fn = let basename = Filename.basename fn in if String.length basename >= 2 && basename.[0] = '*' && basename.[1] = '.' then begin let ext_len = (String.length basename) - 2 in let ext = String.sub basename 2 ext_len in let dirname = Filename.dirname fn in Array.fold_left (fun acc fn -> try let fn_ext = String.sub fn ((String.length fn) - ext_len) ext_len in if fn_ext = ext then (Filename.concat dirname fn) :: acc else acc with Invalid_argument _ -> acc) [] (Sys.readdir dirname) end else begin if file_exists_case fn then [fn] else [] end end # 2893 "setup.ml" module BaseEnvLight = struct (* # 22 "src/base/BaseEnvLight.ml" *) module MapString = Map.Make(String) type t = string MapString.t let default_filename = Filename.concat (Sys.getcwd ()) "setup.data" let load ?(allow_empty=false) ?(filename=default_filename) () = if Sys.file_exists filename then begin let chn = open_in_bin filename in let st = Stream.of_channel chn in let line = ref 1 in let st_line = Stream.from (fun _ -> try match Stream.next st with | '\n' -> incr line; Some '\n' | c -> Some c with Stream.Failure -> None) in let lexer = Genlex.make_lexer ["="] st_line in let rec read_file mp = match Stream.npeek 3 lexer with | [Genlex.Ident nm; Genlex.Kwd "="; Genlex.String value] -> Stream.junk lexer; Stream.junk lexer; Stream.junk lexer; read_file (MapString.add nm value mp) | [] -> mp | _ -> failwith (Printf.sprintf "Malformed data file '%s' line %d" filename !line) in let mp = read_file MapString.empty in close_in chn; mp end else if allow_empty then begin MapString.empty end else begin failwith (Printf.sprintf "Unable to load environment, the file '%s' doesn't exist." filename) end let rec var_expand str env = let buff = Buffer.create ((String.length str) * 2) in Buffer.add_substitute buff (fun var -> try var_expand (MapString.find var env) env with Not_found -> failwith (Printf.sprintf "No variable %s defined when trying to expand %S." var str)) str; Buffer.contents buff let var_get name env = var_expand (MapString.find name env) env let var_choose lst env = OASISExpr.choose (fun nm -> var_get nm env) lst end # 2998 "setup.ml" module BaseContext = struct (* # 22 "src/base/BaseContext.ml" *) (* TODO: get rid of this module. *) open OASISContext let args () = fst (fspecs ()) let default = default end module BaseMessage = struct (* # 22 "src/base/BaseMessage.ml" *) (** Message to user, overrid for Base @author Sylvain Le Gall *) open OASISMessage open BaseContext let debug fmt = debug ~ctxt:!default fmt let info fmt = info ~ctxt:!default fmt let warning fmt = warning ~ctxt:!default fmt let error fmt = error ~ctxt:!default fmt end module BaseEnv = struct (* # 22 "src/base/BaseEnv.ml" *) open OASISGettext open OASISUtils open PropList module MapString = BaseEnvLight.MapString type origin_t = | ODefault | OGetEnv | OFileLoad | OCommandLine type cli_handle_t = | CLINone | CLIAuto | CLIWith | CLIEnable | CLIUser of (Arg.key * Arg.spec * Arg.doc) list type definition_t = { hide: bool; dump: bool; cli: cli_handle_t; arg_help: string option; group: string option; } let schema = Schema.create "environment" (* Environment data *) let env = Data.create () (* Environment data from file *) let env_from_file = ref MapString.empty (* Lexer for var *) let var_lxr = Genlex.make_lexer [] let rec var_expand str = let buff = Buffer.create ((String.length str) * 2) in Buffer.add_substitute buff (fun var -> try (* TODO: this is a quick hack to allow calling Test.Command * without defining executable name really. I.e. if there is * an exec Executable toto, then $(toto) should be replace * by its real name. It is however useful to have this function * for other variable that depend on the host and should be * written better than that. *) let st = var_lxr (Stream.of_string var) in match Stream.npeek 3 st with | [Genlex.Ident "utoh"; Genlex.Ident nm] -> OASISHostPath.of_unix (var_get nm) | [Genlex.Ident "utoh"; Genlex.String s] -> OASISHostPath.of_unix s | [Genlex.Ident "ocaml_escaped"; Genlex.Ident nm] -> String.escaped (var_get nm) | [Genlex.Ident "ocaml_escaped"; Genlex.String s] -> String.escaped s | [Genlex.Ident nm] -> var_get nm | _ -> failwithf (f_ "Unknown expression '%s' in variable expansion of %s.") var str with | Unknown_field (_, _) -> failwithf (f_ "No variable %s defined when trying to expand %S.") var str | Stream.Error e -> failwithf (f_ "Syntax error when parsing '%s' when trying to \ expand %S: %s") var str e) str; Buffer.contents buff and var_get name = let vl = try Schema.get schema env name with Unknown_field _ as e -> begin try MapString.find name !env_from_file with Not_found -> raise e end in var_expand vl let var_choose ?printer ?name lst = OASISExpr.choose ?printer ?name var_get lst let var_protect vl = let buff = Buffer.create (String.length vl) in String.iter (function | '$' -> Buffer.add_string buff "\\$" | c -> Buffer.add_char buff c) vl; Buffer.contents buff let var_define ?(hide=false) ?(dump=true) ?short_desc ?(cli=CLINone) ?arg_help ?group name (* TODO: type constraint on the fact that name must be a valid OCaml id *) dflt = let default = [ OFileLoad, (fun () -> MapString.find name !env_from_file); ODefault, dflt; OGetEnv, (fun () -> Sys.getenv name); ] in let extra = { hide = hide; dump = dump; cli = cli; arg_help = arg_help; group = group; } in (* Try to find a value that can be defined *) let var_get_low lst = let errors, res = List.fold_left (fun (errors, res) (o, v) -> if res = None then begin try errors, Some (v ()) with | Not_found -> errors, res | Failure rsn -> (rsn :: errors), res | e -> (Printexc.to_string e) :: errors, res end else errors, res) ([], None) (List.sort (fun (o1, _) (o2, _) -> Pervasives.compare o2 o1) lst) in match res, errors with | Some v, _ -> v | None, [] -> raise (Not_set (name, None)) | None, lst -> raise (Not_set (name, Some (String.concat (s_ ", ") lst))) in let help = match short_desc with | Some fs -> Some fs | None -> None in let var_get_lst = FieldRO.create ~schema ~name ~parse:(fun ?(context=ODefault) s -> [context, fun () -> s]) ~print:var_get_low ~default ~update:(fun ?context x old_x -> x @ old_x) ?help extra in fun () -> var_expand (var_get_low (var_get_lst env)) let var_redefine ?hide ?dump ?short_desc ?cli ?arg_help ?group name dflt = if Schema.mem schema name then begin (* TODO: look suspsicious, we want to memorize dflt not dflt () *) Schema.set schema env ~context:ODefault name (dflt ()); fun () -> var_get name end else begin var_define ?hide ?dump ?short_desc ?cli ?arg_help ?group name dflt end let var_ignore (e: unit -> string) = () let print_hidden = var_define ~hide:true ~dump:false ~cli:CLIAuto ~arg_help:"Print even non-printable variable. (debug)" "print_hidden" (fun () -> "false") let var_all () = List.rev (Schema.fold (fun acc nm def _ -> if not def.hide || bool_of_string (print_hidden ()) then nm :: acc else acc) [] schema) let default_filename = BaseEnvLight.default_filename let load ?allow_empty ?filename () = env_from_file := BaseEnvLight.load ?allow_empty ?filename () let unload () = env_from_file := MapString.empty; Data.clear env let dump ?(filename=default_filename) () = let chn = open_out_bin filename in let output nm value = Printf.fprintf chn "%s=%S\n" nm value in let mp_todo = (* Dump data from schema *) Schema.fold (fun mp_todo nm def _ -> if def.dump then begin try let value = Schema.get schema env nm in output nm value with Not_set _ -> () end; MapString.remove nm mp_todo) !env_from_file schema in (* Dump data defined outside of schema *) MapString.iter output mp_todo; (* End of the dump *) close_out chn let print () = let printable_vars = Schema.fold (fun acc nm def short_descr_opt -> if not def.hide || bool_of_string (print_hidden ()) then begin try let value = Schema.get schema env nm in let txt = match short_descr_opt with | Some s -> s () | None -> nm in (txt, value) :: acc with Not_set _ -> acc end else acc) [] schema in let max_length = List.fold_left max 0 (List.rev_map String.length (List.rev_map fst printable_vars)) in let dot_pad str = String.make ((max_length - (String.length str)) + 3) '.' in Printf.printf "\nConfiguration: \n"; List.iter (fun (name, value) -> Printf.printf "%s: %s %s\n" name (dot_pad name) value) (List.rev printable_vars); Printf.printf "\n%!" let args () = let arg_concat = OASISUtils.varname_concat ~hyphen:'-' in [ "--override", Arg.Tuple ( let rvr = ref "" in let rvl = ref "" in [ Arg.Set_string rvr; Arg.Set_string rvl; Arg.Unit (fun () -> Schema.set schema env ~context:OCommandLine !rvr !rvl) ] ), "var+val Override any configuration variable."; ] @ List.flatten (Schema.fold (fun acc name def short_descr_opt -> let var_set s = Schema.set schema env ~context:OCommandLine name s in let arg_name = OASISUtils.varname_of_string ~hyphen:'-' name in let hlp = match short_descr_opt with | Some txt -> txt () | None -> "" in let arg_hlp = match def.arg_help with | Some s -> s | None -> "str" in let default_value = try Printf.sprintf (f_ " [%s]") (Schema.get schema env name) with Not_set _ -> "" in let args = match def.cli with | CLINone -> [] | CLIAuto -> [ arg_concat "--" arg_name, Arg.String var_set, Printf.sprintf (f_ "%s %s%s") arg_hlp hlp default_value ] | CLIWith -> [ arg_concat "--with-" arg_name, Arg.String var_set, Printf.sprintf (f_ "%s %s%s") arg_hlp hlp default_value ] | CLIEnable -> let dflt = if default_value = " [true]" then s_ " [default: enabled]" else s_ " [default: disabled]" in [ arg_concat "--enable-" arg_name, Arg.Unit (fun () -> var_set "true"), Printf.sprintf (f_ " %s%s") hlp dflt; arg_concat "--disable-" arg_name, Arg.Unit (fun () -> var_set "false"), Printf.sprintf (f_ " %s%s") hlp dflt ] | CLIUser lst -> lst in args :: acc) [] schema) end module BaseArgExt = struct (* # 22 "src/base/BaseArgExt.ml" *) open OASISUtils open OASISGettext let parse argv args = (* Simulate command line for Arg *) let current = ref 0 in try Arg.parse_argv ~current:current (Array.concat [[|"none"|]; argv]) (Arg.align args) (failwithf (f_ "Don't know what to do with arguments: '%s'")) (s_ "configure options:") with | Arg.Help txt -> print_endline txt; exit 0 | Arg.Bad txt -> prerr_endline txt; exit 1 end module BaseCheck = struct (* # 22 "src/base/BaseCheck.ml" *) open BaseEnv open BaseMessage open OASISUtils open OASISGettext let prog_best prg prg_lst = var_redefine prg (fun () -> let alternate = List.fold_left (fun res e -> match res with | Some _ -> res | None -> try Some (OASISFileUtil.which ~ctxt:!BaseContext.default e) with Not_found -> None) None prg_lst in match alternate with | Some prg -> prg | None -> raise Not_found) let prog prg = prog_best prg [prg] let prog_opt prg = prog_best prg [prg^".opt"; prg] let ocamlfind = prog "ocamlfind" let version var_prefix cmp fversion () = (* Really compare version provided *) let var = var_prefix^"_version_"^(OASISVersion.varname_of_comparator cmp) in var_redefine ~hide:true var (fun () -> let version_str = match fversion () with | "[Distributed with OCaml]" -> begin try (var_get "ocaml_version") with Not_found -> warning (f_ "Variable ocaml_version not defined, fallback \ to default"); Sys.ocaml_version end | res -> res in let version = OASISVersion.version_of_string version_str in if OASISVersion.comparator_apply version cmp then version_str else failwithf (f_ "Cannot satisfy version constraint on %s: %s (version: %s)") var_prefix (OASISVersion.string_of_comparator cmp) version_str) () let package_version pkg = OASISExec.run_read_one_line ~ctxt:!BaseContext.default (ocamlfind ()) ["query"; "-format"; "%v"; pkg] let package ?version_comparator pkg () = let var = OASISUtils.varname_concat "pkg_" (OASISUtils.varname_of_string pkg) in let findlib_dir pkg = let dir = OASISExec.run_read_one_line ~ctxt:!BaseContext.default (ocamlfind ()) ["query"; "-format"; "%d"; pkg] in if Sys.file_exists dir && Sys.is_directory dir then dir else failwithf (f_ "When looking for findlib package %s, \ directory %s return doesn't exist") pkg dir in let vl = var_redefine var (fun () -> findlib_dir pkg) () in ( match version_comparator with | Some ver_cmp -> ignore (version var ver_cmp (fun _ -> package_version pkg) ()) | None -> () ); vl end module BaseOCamlcConfig = struct (* # 22 "src/base/BaseOCamlcConfig.ml" *) open BaseEnv open OASISUtils open OASISGettext module SMap = Map.Make(String) let ocamlc = BaseCheck.prog_opt "ocamlc" let ocamlc_config_map = (* Map name to value for ocamlc -config output (name ^": "^value) *) let rec split_field mp lst = match lst with | line :: tl -> let mp = try let pos_semicolon = String.index line ':' in if pos_semicolon > 1 then ( let name = String.sub line 0 pos_semicolon in let linelen = String.length line in let value = if linelen > pos_semicolon + 2 then String.sub line (pos_semicolon + 2) (linelen - pos_semicolon - 2) else "" in SMap.add name value mp ) else ( mp ) with Not_found -> ( mp ) in split_field mp tl | [] -> mp in let cache = lazy (var_protect (Marshal.to_string (split_field SMap.empty (OASISExec.run_read_output ~ctxt:!BaseContext.default (ocamlc ()) ["-config"])) [])) in var_redefine "ocamlc_config_map" ~hide:true ~dump:false (fun () -> (* TODO: update if ocamlc change !!! *) Lazy.force cache) let var_define nm = (* Extract data from ocamlc -config *) let avlbl_config_get () = Marshal.from_string (ocamlc_config_map ()) 0 in let chop_version_suffix s = try String.sub s 0 (String.index s '+') with _ -> s in let nm_config, value_config = match nm with | "ocaml_version" -> "version", chop_version_suffix | _ -> nm, (fun x -> x) in var_redefine nm (fun () -> try let map = avlbl_config_get () in let value = SMap.find nm_config map in value_config value with Not_found -> failwithf (f_ "Cannot find field '%s' in '%s -config' output") nm (ocamlc ())) end module BaseStandardVar = struct (* # 22 "src/base/BaseStandardVar.ml" *) open OASISGettext open OASISTypes open OASISExpr open BaseCheck open BaseEnv let ocamlfind = BaseCheck.ocamlfind let ocamlc = BaseOCamlcConfig.ocamlc let ocamlopt = prog_opt "ocamlopt" let ocamlbuild = prog "ocamlbuild" (**/**) let rpkg = ref None let pkg_get () = match !rpkg with | Some pkg -> pkg | None -> failwith (s_ "OASIS Package is not set") let var_cond = ref [] let var_define_cond ~since_version f dflt = let holder = ref (fun () -> dflt) in let since_version = OASISVersion.VGreaterEqual (OASISVersion.version_of_string since_version) in var_cond := (fun ver -> if OASISVersion.comparator_apply ver since_version then holder := f ()) :: !var_cond; fun () -> !holder () (**/**) let pkg_name = var_define ~short_desc:(fun () -> s_ "Package name") "pkg_name" (fun () -> (pkg_get ()).name) let pkg_version = var_define ~short_desc:(fun () -> s_ "Package version") "pkg_version" (fun () -> (OASISVersion.string_of_version (pkg_get ()).version)) let c = BaseOCamlcConfig.var_define let os_type = c "os_type" let system = c "system" let architecture = c "architecture" let ccomp_type = c "ccomp_type" let ocaml_version = c "ocaml_version" (* TODO: Check standard variable presence at runtime *) let standard_library_default = c "standard_library_default" let standard_library = c "standard_library" let standard_runtime = c "standard_runtime" let bytecomp_c_compiler = c "bytecomp_c_compiler" let native_c_compiler = c "native_c_compiler" let model = c "model" let ext_obj = c "ext_obj" let ext_asm = c "ext_asm" let ext_lib = c "ext_lib" let ext_dll = c "ext_dll" let default_executable_name = c "default_executable_name" let systhread_supported = c "systhread_supported" let flexlink = BaseCheck.prog "flexlink" let flexdll_version = var_define ~short_desc:(fun () -> "FlexDLL version (Win32)") "flexdll_version" (fun () -> let lst = OASISExec.run_read_output ~ctxt:!BaseContext.default (flexlink ()) ["-help"] in match lst with | line :: _ -> Scanf.sscanf line "FlexDLL version %s" (fun ver -> ver) | [] -> raise Not_found) (**/**) let p name hlp dflt = var_define ~short_desc:hlp ~cli:CLIAuto ~arg_help:"dir" name dflt let (/) a b = if os_type () = Sys.os_type then Filename.concat a b else if os_type () = "Unix" then OASISUnixPath.concat a b else OASISUtils.failwithf (f_ "Cannot handle os_type %s filename concat") (os_type ()) (**/**) let prefix = p "prefix" (fun () -> s_ "Install architecture-independent files dir") (fun () -> match os_type () with | "Win32" -> let program_files = Sys.getenv "PROGRAMFILES" in program_files/(pkg_name ()) | _ -> "/usr/local") let exec_prefix = p "exec_prefix" (fun () -> s_ "Install architecture-dependent files in dir") (fun () -> "$prefix") let bindir = p "bindir" (fun () -> s_ "User executables") (fun () -> "$exec_prefix"/"bin") let sbindir = p "sbindir" (fun () -> s_ "System admin executables") (fun () -> "$exec_prefix"/"sbin") let libexecdir = p "libexecdir" (fun () -> s_ "Program executables") (fun () -> "$exec_prefix"/"libexec") let sysconfdir = p "sysconfdir" (fun () -> s_ "Read-only single-machine data") (fun () -> "$prefix"/"etc") let sharedstatedir = p "sharedstatedir" (fun () -> s_ "Modifiable architecture-independent data") (fun () -> "$prefix"/"com") let localstatedir = p "localstatedir" (fun () -> s_ "Modifiable single-machine data") (fun () -> "$prefix"/"var") let libdir = p "libdir" (fun () -> s_ "Object code libraries") (fun () -> "$exec_prefix"/"lib") let datarootdir = p "datarootdir" (fun () -> s_ "Read-only arch-independent data root") (fun () -> "$prefix"/"share") let datadir = p "datadir" (fun () -> s_ "Read-only architecture-independent data") (fun () -> "$datarootdir") let infodir = p "infodir" (fun () -> s_ "Info documentation") (fun () -> "$datarootdir"/"info") let localedir = p "localedir" (fun () -> s_ "Locale-dependent data") (fun () -> "$datarootdir"/"locale") let mandir = p "mandir" (fun () -> s_ "Man documentation") (fun () -> "$datarootdir"/"man") let docdir = p "docdir" (fun () -> s_ "Documentation root") (fun () -> "$datarootdir"/"doc"/"$pkg_name") let htmldir = p "htmldir" (fun () -> s_ "HTML documentation") (fun () -> "$docdir") let dvidir = p "dvidir" (fun () -> s_ "DVI documentation") (fun () -> "$docdir") let pdfdir = p "pdfdir" (fun () -> s_ "PDF documentation") (fun () -> "$docdir") let psdir = p "psdir" (fun () -> s_ "PS documentation") (fun () -> "$docdir") let destdir = p "destdir" (fun () -> s_ "Prepend a path when installing package") (fun () -> raise (PropList.Not_set ("destdir", Some (s_ "undefined by construct")))) let findlib_version = var_define "findlib_version" (fun () -> BaseCheck.package_version "findlib") let is_native = var_define "is_native" (fun () -> try let _s: string = ocamlopt () in "true" with PropList.Not_set _ -> let _s: string = ocamlc () in "false") let ext_program = var_define "suffix_program" (fun () -> match os_type () with | "Win32" | "Cygwin" -> ".exe" | _ -> "") let rm = var_define ~short_desc:(fun () -> s_ "Remove a file.") "rm" (fun () -> match os_type () with | "Win32" -> "del" | _ -> "rm -f") let rmdir = var_define ~short_desc:(fun () -> s_ "Remove a directory.") "rmdir" (fun () -> match os_type () with | "Win32" -> "rd" | _ -> "rm -rf") let debug = var_define ~short_desc:(fun () -> s_ "Turn ocaml debug flag on") ~cli:CLIEnable "debug" (fun () -> "true") let profile = var_define ~short_desc:(fun () -> s_ "Turn ocaml profile flag on") ~cli:CLIEnable "profile" (fun () -> "false") let tests = var_define_cond ~since_version:"0.3" (fun () -> var_define ~short_desc:(fun () -> s_ "Compile tests executable and library and run them") ~cli:CLIEnable "tests" (fun () -> "false")) "true" let docs = var_define_cond ~since_version:"0.3" (fun () -> var_define ~short_desc:(fun () -> s_ "Create documentations") ~cli:CLIEnable "docs" (fun () -> "true")) "true" let native_dynlink = var_define ~short_desc:(fun () -> s_ "Compiler support generation of .cmxs.") ~cli:CLINone "native_dynlink" (fun () -> let res = let ocaml_lt_312 () = OASISVersion.comparator_apply (OASISVersion.version_of_string (ocaml_version ())) (OASISVersion.VLesser (OASISVersion.version_of_string "3.12.0")) in let flexdll_lt_030 () = OASISVersion.comparator_apply (OASISVersion.version_of_string (flexdll_version ())) (OASISVersion.VLesser (OASISVersion.version_of_string "0.30")) in let has_native_dynlink = let ocamlfind = ocamlfind () in try let fn = OASISExec.run_read_one_line ~ctxt:!BaseContext.default ocamlfind ["query"; "-predicates"; "native"; "dynlink"; "-format"; "%d/%a"] in Sys.file_exists fn with _ -> false in if not has_native_dynlink then false else if ocaml_lt_312 () then false else if (os_type () = "Win32" || os_type () = "Cygwin") && flexdll_lt_030 () then begin BaseMessage.warning (f_ ".cmxs generation disabled because FlexDLL needs to be \ at least 0.30. Please upgrade FlexDLL from %s to 0.30.") (flexdll_version ()); false end else true in string_of_bool res) let init pkg = rpkg := Some pkg; List.iter (fun f -> f pkg.oasis_version) !var_cond end module BaseFileAB = struct (* # 22 "src/base/BaseFileAB.ml" *) open BaseEnv open OASISGettext open BaseMessage let to_filename fn = let fn = OASISHostPath.of_unix fn in if not (Filename.check_suffix fn ".ab") then warning (f_ "File '%s' doesn't have '.ab' extension") fn; Filename.chop_extension fn let replace fn_lst = let buff = Buffer.create 13 in List.iter (fun fn -> let fn = OASISHostPath.of_unix fn in let chn_in = open_in fn in let chn_out = open_out (to_filename fn) in ( try while true do Buffer.add_string buff (var_expand (input_line chn_in)); Buffer.add_char buff '\n' done with End_of_file -> () ); Buffer.output_buffer chn_out buff; Buffer.clear buff; close_in chn_in; close_out chn_out) fn_lst end module BaseLog = struct (* # 22 "src/base/BaseLog.ml" *) open OASISUtils let default_filename = Filename.concat (Filename.dirname BaseEnv.default_filename) "setup.log" module SetTupleString = Set.Make (struct type t = string * string let compare (s11, s12) (s21, s22) = match String.compare s11 s21 with | 0 -> String.compare s12 s22 | n -> n end) let load () = if Sys.file_exists default_filename then begin let chn = open_in default_filename in let scbuf = Scanf.Scanning.from_file default_filename in let rec read_aux (st, lst) = if not (Scanf.Scanning.end_of_input scbuf) then begin let acc = try Scanf.bscanf scbuf "%S %S\n" (fun e d -> let t = e, d in if SetTupleString.mem t st then st, lst else SetTupleString.add t st, t :: lst) with Scanf.Scan_failure _ -> failwith (Scanf.bscanf scbuf "%l" (fun line -> Printf.sprintf "Malformed log file '%s' at line %d" default_filename line)) in read_aux acc end else begin close_in chn; List.rev lst end in read_aux (SetTupleString.empty, []) end else begin [] end let register event data = let chn_out = open_out_gen [Open_append; Open_creat; Open_text] 0o644 default_filename in Printf.fprintf chn_out "%S %S\n" event data; close_out chn_out let unregister event data = if Sys.file_exists default_filename then begin let lst = load () in let chn_out = open_out default_filename in let write_something = ref false in List.iter (fun (e, d) -> if e <> event || d <> data then begin write_something := true; Printf.fprintf chn_out "%S %S\n" e d end) lst; close_out chn_out; if not !write_something then Sys.remove default_filename end let filter events = let st_events = List.fold_left (fun st e -> SetString.add e st) SetString.empty events in List.filter (fun (e, _) -> SetString.mem e st_events) (load ()) let exists event data = List.exists (fun v -> (event, data) = v) (load ()) end module BaseBuilt = struct (* # 22 "src/base/BaseBuilt.ml" *) open OASISTypes open OASISGettext open BaseStandardVar open BaseMessage type t = | BExec (* Executable *) | BExecLib (* Library coming with executable *) | BLib (* Library *) | BObj (* Library *) | BDoc (* Document *) let to_log_event_file t nm = "built_"^ (match t with | BExec -> "exec" | BExecLib -> "exec_lib" | BLib -> "lib" | BObj -> "obj" | BDoc -> "doc")^ "_"^nm let to_log_event_done t nm = "is_"^(to_log_event_file t nm) let register t nm lst = BaseLog.register (to_log_event_done t nm) "true"; List.iter (fun alt -> let registered = List.fold_left (fun registered fn -> if OASISFileUtil.file_exists_case fn then begin BaseLog.register (to_log_event_file t nm) (if Filename.is_relative fn then Filename.concat (Sys.getcwd ()) fn else fn); true end else registered) false alt in if not registered then warning (f_ "Cannot find an existing alternative files among: %s") (String.concat (s_ ", ") alt)) lst let unregister t nm = List.iter (fun (e, d) -> BaseLog.unregister e d) (BaseLog.filter [to_log_event_file t nm; to_log_event_done t nm]) let fold t nm f acc = List.fold_left (fun acc (_, fn) -> if OASISFileUtil.file_exists_case fn then begin f acc fn end else begin warning (f_ "File '%s' has been marked as built \ for %s but doesn't exist") fn (Printf.sprintf (match t with | BExec | BExecLib -> (f_ "executable %s") | BLib -> (f_ "library %s") | BObj -> (f_ "object %s") | BDoc -> (f_ "documentation %s")) nm); acc end) acc (BaseLog.filter [to_log_event_file t nm]) let is_built t nm = List.fold_left (fun is_built (_, d) -> (try bool_of_string d with _ -> false)) false (BaseLog.filter [to_log_event_done t nm]) let of_executable ffn (cs, bs, exec) = let unix_exec_is, unix_dll_opt = OASISExecutable.unix_exec_is (cs, bs, exec) (fun () -> bool_of_string (is_native ())) ext_dll ext_program in let evs = (BExec, cs.cs_name, [[ffn unix_exec_is]]) :: (match unix_dll_opt with | Some fn -> [BExecLib, cs.cs_name, [[ffn fn]]] | None -> []) in evs, unix_exec_is, unix_dll_opt let of_library ffn (cs, bs, lib) = let unix_lst = OASISLibrary.generated_unix_files ~ctxt:!BaseContext.default ~source_file_exists:(fun fn -> OASISFileUtil.file_exists_case (OASISHostPath.of_unix fn)) ~is_native:(bool_of_string (is_native ())) ~has_native_dynlink:(bool_of_string (native_dynlink ())) ~ext_lib:(ext_lib ()) ~ext_dll:(ext_dll ()) (cs, bs, lib) in let evs = [BLib, cs.cs_name, List.map (List.map ffn) unix_lst] in evs, unix_lst let of_object ffn (cs, bs, obj) = let unix_lst = OASISObject.generated_unix_files ~ctxt:!BaseContext.default ~source_file_exists:(fun fn -> OASISFileUtil.file_exists_case (OASISHostPath.of_unix fn)) ~is_native:(bool_of_string (is_native ())) (cs, bs, obj) in let evs = [BObj, cs.cs_name, List.map (List.map ffn) unix_lst] in evs, unix_lst end module BaseCustom = struct (* # 22 "src/base/BaseCustom.ml" *) open BaseEnv open BaseMessage open OASISTypes open OASISGettext let run cmd args extra_args = OASISExec.run ~ctxt:!BaseContext.default ~quote:false (var_expand cmd) (List.map var_expand (args @ (Array.to_list extra_args))) let hook ?(failsafe=false) cstm f e = let optional_command lst = let printer = function | Some (cmd, args) -> String.concat " " (cmd :: args) | None -> s_ "No command" in match var_choose ~name:(s_ "Pre/Post Command") ~printer lst with | Some (cmd, args) -> begin try run cmd args [||] with e when failsafe -> warning (f_ "Command '%s' fail with error: %s") (String.concat " " (cmd :: args)) (match e with | Failure msg -> msg | e -> Printexc.to_string e) end | None -> () in let res = optional_command cstm.pre_command; f e in optional_command cstm.post_command; res end module BaseDynVar = struct (* # 22 "src/base/BaseDynVar.ml" *) open OASISTypes open OASISGettext open BaseEnv open BaseBuilt let init pkg = (* TODO: disambiguate exec vs other variable by adding exec_VARNAME. *) (* TODO: provide compile option for library libary_byte_args_VARNAME... *) List.iter (function | Executable (cs, bs, exec) -> if var_choose bs.bs_build then var_ignore (var_redefine (* We don't save this variable *) ~dump:false ~short_desc:(fun () -> Printf.sprintf (f_ "Filename of executable '%s'") cs.cs_name) (OASISUtils.varname_of_string cs.cs_name) (fun () -> let fn_opt = fold BExec cs.cs_name (fun _ fn -> Some fn) None in match fn_opt with | Some fn -> fn | None -> raise (PropList.Not_set (cs.cs_name, Some (Printf.sprintf (f_ "Executable '%s' not yet built.") cs.cs_name))))) | Library _ | Object _ | Flag _ | Test _ | SrcRepo _ | Doc _ -> ()) pkg.sections end module BaseTest = struct (* # 22 "src/base/BaseTest.ml" *) open BaseEnv open BaseMessage open OASISTypes open OASISExpr open OASISGettext let test lst pkg extra_args = let one_test (failure, n) (test_plugin, cs, test) = if var_choose ~name:(Printf.sprintf (f_ "test %s run") cs.cs_name) ~printer:string_of_bool test.test_run then begin let () = info (f_ "Running test '%s'") cs.cs_name in let back_cwd = match test.test_working_directory with | Some dir -> let cwd = Sys.getcwd () in let chdir d = info (f_ "Changing directory to '%s'") d; Sys.chdir d in chdir dir; fun () -> chdir cwd | None -> fun () -> () in try let failure_percent = BaseCustom.hook test.test_custom (test_plugin pkg (cs, test)) extra_args in back_cwd (); (failure_percent +. failure, n + 1) with e -> begin back_cwd (); raise e end end else begin info (f_ "Skipping test '%s'") cs.cs_name; (failure, n) end in let failed, n = List.fold_left one_test (0.0, 0) lst in let failure_percent = if n = 0 then 0.0 else failed /. (float_of_int n) in let msg = Printf.sprintf (f_ "Tests had a %.2f%% failure rate") (100. *. failure_percent) in if failure_percent > 0.0 then failwith msg else info "%s" msg; (* Possible explanation why the tests where not run. *) if OASISFeatures.package_test OASISFeatures.flag_tests pkg && not (bool_of_string (BaseStandardVar.tests ())) && lst <> [] then BaseMessage.warning "Tests are turned off, consider enabling with \ 'ocaml setup.ml -configure --enable-tests'" end module BaseDoc = struct (* # 22 "src/base/BaseDoc.ml" *) open BaseEnv open BaseMessage open OASISTypes open OASISGettext let doc lst pkg extra_args = let one_doc (doc_plugin, cs, doc) = if var_choose ~name:(Printf.sprintf (f_ "documentation %s build") cs.cs_name) ~printer:string_of_bool doc.doc_build then begin info (f_ "Building documentation '%s'") cs.cs_name; BaseCustom.hook doc.doc_custom (doc_plugin pkg (cs, doc)) extra_args end in List.iter one_doc lst; if OASISFeatures.package_test OASISFeatures.flag_docs pkg && not (bool_of_string (BaseStandardVar.docs ())) && lst <> [] then BaseMessage.warning "Docs are turned off, consider enabling with \ 'ocaml setup.ml -configure --enable-docs'" end module BaseSetup = struct (* # 22 "src/base/BaseSetup.ml" *) open BaseEnv open BaseMessage open OASISTypes open OASISSection open OASISGettext open OASISUtils type std_args_fun = package -> string array -> unit type ('a, 'b) section_args_fun = name * (package -> (common_section * 'a) -> string array -> 'b) type t = { configure: std_args_fun; build: std_args_fun; doc: ((doc, unit) section_args_fun) list; test: ((test, float) section_args_fun) list; install: std_args_fun; uninstall: std_args_fun; clean: std_args_fun list; clean_doc: (doc, unit) section_args_fun list; clean_test: (test, unit) section_args_fun list; distclean: std_args_fun list; distclean_doc: (doc, unit) section_args_fun list; distclean_test: (test, unit) section_args_fun list; package: package; oasis_fn: string option; oasis_version: string; oasis_digest: Digest.t option; oasis_exec: string option; oasis_setup_args: string list; setup_update: bool; } (* Associate a plugin function with data from package *) let join_plugin_sections filter_map lst = List.rev (List.fold_left (fun acc sct -> match filter_map sct with | Some e -> e :: acc | None -> acc) [] lst) (* Search for plugin data associated with a section name *) let lookup_plugin_section plugin action nm lst = try List.assoc nm lst with Not_found -> failwithf (f_ "Cannot find plugin %s matching section %s for %s action") plugin nm action let configure t args = (* Run configure *) BaseCustom.hook t.package.conf_custom (fun () -> (* Reload if preconf has changed it *) begin try unload (); load (); with _ -> () end; (* Run plugin's configure *) t.configure t.package args; (* Dump to allow postconf to change it *) dump ()) (); (* Reload environment *) unload (); load (); (* Save environment *) print (); (* Replace data in file *) BaseFileAB.replace t.package.files_ab let build t args = BaseCustom.hook t.package.build_custom (t.build t.package) args let doc t args = BaseDoc.doc (join_plugin_sections (function | Doc (cs, e) -> Some (lookup_plugin_section "documentation" (s_ "build") cs.cs_name t.doc, cs, e) | _ -> None) t.package.sections) t.package args let test t args = BaseTest.test (join_plugin_sections (function | Test (cs, e) -> Some (lookup_plugin_section "test" (s_ "run") cs.cs_name t.test, cs, e) | _ -> None) t.package.sections) t.package args let all t args = let rno_doc = ref false in let rno_test = ref false in let arg_rest = ref [] in Arg.parse_argv ~current:(ref 0) (Array.of_list ((Sys.executable_name^" all") :: (Array.to_list args))) [ "-no-doc", Arg.Set rno_doc, s_ "Don't run doc target"; "-no-test", Arg.Set rno_test, s_ "Don't run test target"; "--", Arg.Rest (fun arg -> arg_rest := arg :: !arg_rest), s_ "All arguments for configure."; ] (failwithf (f_ "Don't know what to do with '%s'")) ""; info "Running configure step"; configure t (Array.of_list (List.rev !arg_rest)); info "Running build step"; build t [||]; (* Load setup.log dynamic variables *) BaseDynVar.init t.package; if not !rno_doc then begin info "Running doc step"; doc t [||]; end else begin info "Skipping doc step" end; if not !rno_test then begin info "Running test step"; test t [||] end else begin info "Skipping test step" end let install t args = BaseCustom.hook t.package.install_custom (t.install t.package) args let uninstall t args = BaseCustom.hook t.package.uninstall_custom (t.uninstall t.package) args let reinstall t args = uninstall t args; install t args let clean, distclean = let failsafe f a = try f a with e -> warning (f_ "Action fail with error: %s") (match e with | Failure msg -> msg | e -> Printexc.to_string e) in let generic_clean t cstm mains docs tests args = BaseCustom.hook ~failsafe:true cstm (fun () -> (* Clean section *) List.iter (function | Test (cs, test) -> let f = try List.assoc cs.cs_name tests with Not_found -> fun _ _ _ -> () in failsafe (f t.package (cs, test)) args | Doc (cs, doc) -> let f = try List.assoc cs.cs_name docs with Not_found -> fun _ _ _ -> () in failsafe (f t.package (cs, doc)) args | Library _ | Object _ | Executable _ | Flag _ | SrcRepo _ -> ()) t.package.sections; (* Clean whole package *) List.iter (fun f -> failsafe (f t.package) args) mains) () in let clean t args = generic_clean t t.package.clean_custom t.clean t.clean_doc t.clean_test args in let distclean t args = (* Call clean *) clean t args; (* Call distclean code *) generic_clean t t.package.distclean_custom t.distclean t.distclean_doc t.distclean_test args; (* Remove generated file *) List.iter (fun fn -> if Sys.file_exists fn then begin info (f_ "Remove '%s'") fn; Sys.remove fn end) (BaseEnv.default_filename :: BaseLog.default_filename :: (List.rev_map BaseFileAB.to_filename t.package.files_ab)) in clean, distclean let version t _ = print_endline t.oasis_version let update_setup_ml, no_update_setup_ml_cli = let b = ref true in b, ("-no-update-setup-ml", Arg.Clear b, s_ " Don't try to update setup.ml, even if _oasis has changed.") let default_oasis_fn = "_oasis" let update_setup_ml t = let oasis_fn = match t.oasis_fn with | Some fn -> fn | None -> default_oasis_fn in let oasis_exec = match t.oasis_exec with | Some fn -> fn | None -> "oasis" in let ocaml = Sys.executable_name in let setup_ml, args = match Array.to_list Sys.argv with | setup_ml :: args -> setup_ml, args | [] -> failwith (s_ "Expecting non-empty command line arguments.") in let ocaml, setup_ml = if Sys.executable_name = Sys.argv.(0) then (* We are not running in standard mode, probably the script * is precompiled. *) "ocaml", "setup.ml" else ocaml, setup_ml in let no_update_setup_ml_cli, _, _ = no_update_setup_ml_cli in let do_update () = let oasis_exec_version = OASISExec.run_read_one_line ~ctxt:!BaseContext.default ~f_exit_code: (function | 0 -> () | 1 -> failwithf (f_ "Executable '%s' is probably an old version \ of oasis (< 0.3.0), please update to version \ v%s.") oasis_exec t.oasis_version | 127 -> failwithf (f_ "Cannot find executable '%s', please install \ oasis v%s.") oasis_exec t.oasis_version | n -> failwithf (f_ "Command '%s version' exited with code %d.") oasis_exec n) oasis_exec ["version"] in if OASISVersion.comparator_apply (OASISVersion.version_of_string oasis_exec_version) (OASISVersion.VGreaterEqual (OASISVersion.version_of_string t.oasis_version)) then begin (* We have a version >= for the executable oasis, proceed with * update. *) (* TODO: delegate this check to 'oasis setup'. *) if Sys.os_type = "Win32" then failwithf (f_ "It is not possible to update the running script \ setup.ml on Windows. Please update setup.ml by \ running '%s'.") (String.concat " " (oasis_exec :: "setup" :: t.oasis_setup_args)) else begin OASISExec.run ~ctxt:!BaseContext.default ~f_exit_code: (function | 0 -> () | n -> failwithf (f_ "Unable to update setup.ml using '%s', \ please fix the problem and retry.") oasis_exec) oasis_exec ("setup" :: t.oasis_setup_args); OASISExec.run ~ctxt:!BaseContext.default ocaml (setup_ml :: args) end end else failwithf (f_ "The version of '%s' (v%s) doesn't match the version of \ oasis used to generate the %s file. Please install at \ least oasis v%s.") oasis_exec oasis_exec_version setup_ml t.oasis_version in if !update_setup_ml then begin try match t.oasis_digest with | Some dgst -> if Sys.file_exists oasis_fn && dgst <> Digest.file default_oasis_fn then begin do_update (); true end else false | None -> false with e -> error (f_ "Error when updating setup.ml. If you want to avoid this error, \ you can bypass the update of %s by running '%s %s %s %s'") setup_ml ocaml setup_ml no_update_setup_ml_cli (String.concat " " args); raise e end else false let setup t = let catch_exn = ref true in try let act_ref = ref (fun _ -> failwithf (f_ "No action defined, run '%s %s -help'") Sys.executable_name Sys.argv.(0)) in let extra_args_ref = ref [] in let allow_empty_env_ref = ref false in let arg_handle ?(allow_empty_env=false) act = Arg.Tuple [ Arg.Rest (fun str -> extra_args_ref := str :: !extra_args_ref); Arg.Unit (fun () -> allow_empty_env_ref := allow_empty_env; act_ref := act); ] in Arg.parse (Arg.align ([ "-configure", arg_handle ~allow_empty_env:true configure, s_ "[options*] Configure the whole build process."; "-build", arg_handle build, s_ "[options*] Build executables and libraries."; "-doc", arg_handle doc, s_ "[options*] Build documents."; "-test", arg_handle test, s_ "[options*] Run tests."; "-all", arg_handle ~allow_empty_env:true all, s_ "[options*] Run configure, build, doc and test targets."; "-install", arg_handle install, s_ "[options*] Install libraries, data, executables \ and documents."; "-uninstall", arg_handle uninstall, s_ "[options*] Uninstall libraries, data, executables \ and documents."; "-reinstall", arg_handle reinstall, s_ "[options*] Uninstall and install libraries, data, \ executables and documents."; "-clean", arg_handle ~allow_empty_env:true clean, s_ "[options*] Clean files generated by a build."; "-distclean", arg_handle ~allow_empty_env:true distclean, s_ "[options*] Clean files generated by a build and configure."; "-version", arg_handle ~allow_empty_env:true version, s_ " Display version of OASIS used to generate this setup.ml."; "-no-catch-exn", Arg.Clear catch_exn, s_ " Don't catch exception, useful for debugging."; ] @ (if t.setup_update then [no_update_setup_ml_cli] else []) @ (BaseContext.args ()))) (failwithf (f_ "Don't know what to do with '%s'")) (s_ "Setup and run build process current package\n"); (* Build initial environment *) load ~allow_empty:!allow_empty_env_ref (); (** Initialize flags *) List.iter (function | Flag (cs, {flag_description = hlp; flag_default = choices}) -> begin let apply ?short_desc () = var_ignore (var_define ~cli:CLIEnable ?short_desc (OASISUtils.varname_of_string cs.cs_name) (fun () -> string_of_bool (var_choose ~name:(Printf.sprintf (f_ "default value of flag %s") cs.cs_name) ~printer:string_of_bool choices))) in match hlp with | Some hlp -> apply ~short_desc:(fun () -> hlp) () | None -> apply () end | _ -> ()) t.package.sections; BaseStandardVar.init t.package; BaseDynVar.init t.package; if t.setup_update && update_setup_ml t then () else !act_ref t (Array.of_list (List.rev !extra_args_ref)) with e when !catch_exn -> error "%s" (Printexc.to_string e); exit 1 end # 5409 "setup.ml" module InternalConfigurePlugin = struct (* # 22 "src/plugins/internal/InternalConfigurePlugin.ml" *) (** Configure using internal scheme @author Sylvain Le Gall *) open BaseEnv open OASISTypes open OASISUtils open OASISGettext open BaseMessage (** Configure build using provided series of check to be done * and then output corresponding file. *) let configure pkg argv = let var_ignore_eval var = let _s: string = var () in () in let errors = ref SetString.empty in let buff = Buffer.create 13 in let add_errors fmt = Printf.kbprintf (fun b -> errors := SetString.add (Buffer.contents b) !errors; Buffer.clear b) buff fmt in let warn_exception e = warning "%s" (Printexc.to_string e) in (* Check tools *) let check_tools lst = List.iter (function | ExternalTool tool -> begin try var_ignore_eval (BaseCheck.prog tool) with e -> warn_exception e; add_errors (f_ "Cannot find external tool '%s'") tool end | InternalExecutable nm1 -> (* Check that matching tool is built *) List.iter (function | Executable ({cs_name = nm2}, {bs_build = build}, _) when nm1 = nm2 -> if not (var_choose build) then add_errors (f_ "Cannot find buildable internal executable \ '%s' when checking build depends") nm1 | _ -> ()) pkg.sections) lst in let build_checks sct bs = if var_choose bs.bs_build then begin if bs.bs_compiled_object = Native then begin try var_ignore_eval BaseStandardVar.ocamlopt with e -> warn_exception e; add_errors (f_ "Section %s requires native compilation") (OASISSection.string_of_section sct) end; (* Check tools *) check_tools bs.bs_build_tools; (* Check depends *) List.iter (function | FindlibPackage (findlib_pkg, version_comparator) -> begin try var_ignore_eval (BaseCheck.package ?version_comparator findlib_pkg) with e -> warn_exception e; match version_comparator with | None -> add_errors (f_ "Cannot find findlib package %s") findlib_pkg | Some ver_cmp -> add_errors (f_ "Cannot find findlib package %s (%s)") findlib_pkg (OASISVersion.string_of_comparator ver_cmp) end | InternalLibrary nm1 -> (* Check that matching library is built *) List.iter (function | Library ({cs_name = nm2}, {bs_build = build}, _) when nm1 = nm2 -> if not (var_choose build) then add_errors (f_ "Cannot find buildable internal library \ '%s' when checking build depends") nm1 | _ -> ()) pkg.sections) bs.bs_build_depends end in (* Parse command line *) BaseArgExt.parse argv (BaseEnv.args ()); (* OCaml version *) begin match pkg.ocaml_version with | Some ver_cmp -> begin try var_ignore_eval (BaseCheck.version "ocaml" ver_cmp BaseStandardVar.ocaml_version) with e -> warn_exception e; add_errors (f_ "OCaml version %s doesn't match version constraint %s") (BaseStandardVar.ocaml_version ()) (OASISVersion.string_of_comparator ver_cmp) end | None -> () end; (* Findlib version *) begin match pkg.findlib_version with | Some ver_cmp -> begin try var_ignore_eval (BaseCheck.version "findlib" ver_cmp BaseStandardVar.findlib_version) with e -> warn_exception e; add_errors (f_ "Findlib version %s doesn't match version constraint %s") (BaseStandardVar.findlib_version ()) (OASISVersion.string_of_comparator ver_cmp) end | None -> () end; (* Make sure the findlib version is fine for the OCaml compiler. *) begin let ocaml_ge4 = OASISVersion.version_compare (OASISVersion.version_of_string (BaseStandardVar.ocaml_version())) (OASISVersion.version_of_string "4.0.0") >= 0 in if ocaml_ge4 then let findlib_lt132 = OASISVersion.version_compare (OASISVersion.version_of_string (BaseStandardVar.findlib_version())) (OASISVersion.version_of_string "1.3.2") < 0 in if findlib_lt132 then add_errors "OCaml >= 4.0.0 requires Findlib version >= 1.3.2" end; (* FlexDLL *) if BaseStandardVar.os_type () = "Win32" || BaseStandardVar.os_type () = "Cygwin" then begin try var_ignore_eval BaseStandardVar.flexlink with e -> warn_exception e; add_errors (f_ "Cannot find 'flexlink'") end; (* Check build depends *) List.iter (function | Executable (_, bs, _) | Library (_, bs, _) as sct -> build_checks sct bs | Doc (_, doc) -> if var_choose doc.doc_build then check_tools doc.doc_build_tools | Test (_, test) -> if var_choose test.test_run then check_tools test.test_tools | _ -> ()) pkg.sections; (* Check if we need native dynlink (presence of libraries that compile to * native) *) begin let has_cmxa = List.exists (function | Library (_, bs, _) -> var_choose bs.bs_build && (bs.bs_compiled_object = Native || (bs.bs_compiled_object = Best && bool_of_string (BaseStandardVar.is_native ()))) | _ -> false) pkg.sections in if has_cmxa then var_ignore_eval BaseStandardVar.native_dynlink end; (* Check errors *) if SetString.empty != !errors then begin List.iter (fun e -> error "%s" e) (SetString.elements !errors); failwithf (fn_ "%d configuration error" "%d configuration errors" (SetString.cardinal !errors)) (SetString.cardinal !errors) end end module InternalInstallPlugin = struct (* # 22 "src/plugins/internal/InternalInstallPlugin.ml" *) (** Install using internal scheme @author Sylvain Le Gall *) open BaseEnv open BaseStandardVar open BaseMessage open OASISTypes open OASISFindlib open OASISGettext open OASISUtils let exec_hook = ref (fun (cs, bs, exec) -> cs, bs, exec) let lib_hook = ref (fun (cs, bs, lib) -> cs, bs, lib, []) let obj_hook = ref (fun (cs, bs, obj) -> cs, bs, obj, []) let doc_hook = ref (fun (cs, doc) -> cs, doc) let install_file_ev = "install-file" let install_dir_ev = "install-dir" let install_findlib_ev = "install-findlib" let win32_max_command_line_length = 8000 let split_install_command ocamlfind findlib_name meta files = if Sys.os_type = "Win32" then (* Arguments for the first command: *) let first_args = ["install"; findlib_name; meta] in (* Arguments for remaining commands: *) let other_args = ["install"; findlib_name; "-add"] in (* Extract as much files as possible from [files], [len] is the current command line length: *) let rec get_files len acc files = match files with | [] -> (List.rev acc, []) | file :: rest -> let len = len + 1 + String.length file in if len > win32_max_command_line_length then (List.rev acc, files) else get_files len (file :: acc) rest in (* Split the command into several commands. *) let rec split args files = match files with | [] -> [] | _ -> (* Length of "ocamlfind install [META|-add]" *) let len = List.fold_left (fun len arg -> len + 1 (* for the space *) + String.length arg) (String.length ocamlfind) args in match get_files len [] files with | ([], _) -> failwith (s_ "Command line too long.") | (firsts, others) -> let cmd = args @ firsts in (* Use -add for remaining commands: *) let () = let findlib_ge_132 = OASISVersion.comparator_apply (OASISVersion.version_of_string (BaseStandardVar.findlib_version ())) (OASISVersion.VGreaterEqual (OASISVersion.version_of_string "1.3.2")) in if not findlib_ge_132 then failwithf (f_ "Installing the library %s require to use the \ flag '-add' of ocamlfind because the command \ line is too long. This flag is only available \ for findlib 1.3.2. Please upgrade findlib from \ %s to 1.3.2") findlib_name (BaseStandardVar.findlib_version ()) in let cmds = split other_args others in cmd :: cmds in (* The first command does not use -add: *) split first_args files else ["install" :: findlib_name :: meta :: files] let install pkg argv = let in_destdir = try let destdir = destdir () in (* Practically speaking destdir is prepended * at the beginning of the target filename *) fun fn -> destdir^fn with PropList.Not_set _ -> fun fn -> fn in let install_file ?tgt_fn src_file envdir = let tgt_dir = in_destdir (envdir ()) in let tgt_file = Filename.concat tgt_dir (match tgt_fn with | Some fn -> fn | None -> Filename.basename src_file) in (* Create target directory if needed *) OASISFileUtil.mkdir_parent ~ctxt:!BaseContext.default (fun dn -> info (f_ "Creating directory '%s'") dn; BaseLog.register install_dir_ev dn) tgt_dir; (* Really install files *) info (f_ "Copying file '%s' to '%s'") src_file tgt_file; OASISFileUtil.cp ~ctxt:!BaseContext.default src_file tgt_file; BaseLog.register install_file_ev tgt_file in (* Install data into defined directory *) let install_data srcdir lst tgtdir = let tgtdir = OASISHostPath.of_unix (var_expand tgtdir) in List.iter (fun (src, tgt_opt) -> let real_srcs = OASISFileUtil.glob ~ctxt:!BaseContext.default (Filename.concat srcdir src) in if real_srcs = [] then failwithf (f_ "Wildcard '%s' doesn't match any files") src; List.iter (fun fn -> install_file fn (fun () -> match tgt_opt with | Some s -> OASISHostPath.of_unix (var_expand s) | None -> tgtdir)) real_srcs) lst in let make_fnames modul sufx = List.fold_right begin fun sufx accu -> (String.capitalize modul ^ sufx) :: (String.uncapitalize modul ^ sufx) :: accu end sufx [] in (** Install all libraries *) let install_libs pkg = let files_of_library (f_data, acc) data_lib = let cs, bs, lib, lib_extra = !lib_hook data_lib in if var_choose bs.bs_install && BaseBuilt.is_built BaseBuilt.BLib cs.cs_name then begin let acc = (* Start with acc + lib_extra *) List.rev_append lib_extra acc in let acc = (* Add uncompiled header from the source tree *) let path = OASISHostPath.of_unix bs.bs_path in List.fold_left begin fun acc modul -> begin try [List.find OASISFileUtil.file_exists_case (List.map (Filename.concat path) (make_fnames modul [".mli"; ".ml"]))] with Not_found -> warning (f_ "Cannot find source header for module %s \ in library %s") modul cs.cs_name; [] end @ List.filter OASISFileUtil.file_exists_case (List.map (Filename.concat path) (make_fnames modul [".annot";".cmti";".cmt"])) @ acc end acc lib.lib_modules in let acc = (* Get generated files *) BaseBuilt.fold BaseBuilt.BLib cs.cs_name (fun acc fn -> fn :: acc) acc in let f_data () = (* Install data associated with the library *) install_data bs.bs_path bs.bs_data_files (Filename.concat (datarootdir ()) pkg.name); f_data () in (f_data, acc) end else begin (f_data, acc) end and files_of_object (f_data, acc) data_obj = let cs, bs, obj, obj_extra = !obj_hook data_obj in if var_choose bs.bs_install && BaseBuilt.is_built BaseBuilt.BObj cs.cs_name then begin let acc = (* Start with acc + obj_extra *) List.rev_append obj_extra acc in let acc = (* Add uncompiled header from the source tree *) let path = OASISHostPath.of_unix bs.bs_path in List.fold_left begin fun acc modul -> begin try [List.find OASISFileUtil.file_exists_case (List.map (Filename.concat path) (make_fnames modul [".mli"; ".ml"]))] with Not_found -> warning (f_ "Cannot find source header for module %s \ in object %s") modul cs.cs_name; [] end @ List.filter OASISFileUtil.file_exists_case (List.map (Filename.concat path) (make_fnames modul [".annot";".cmti";".cmt"])) @ acc end acc obj.obj_modules in let acc = (* Get generated files *) BaseBuilt.fold BaseBuilt.BObj cs.cs_name (fun acc fn -> fn :: acc) acc in let f_data () = (* Install data associated with the object *) install_data bs.bs_path bs.bs_data_files (Filename.concat (datarootdir ()) pkg.name); f_data () in (f_data, acc) end else begin (f_data, acc) end in (* Install one group of library *) let install_group_lib grp = (* Iterate through all group nodes *) let rec install_group_lib_aux data_and_files grp = let data_and_files, children = match grp with | Container (_, children) -> data_and_files, children | Package (_, cs, bs, `Library lib, children) -> files_of_library data_and_files (cs, bs, lib), children | Package (_, cs, bs, `Object obj, children) -> files_of_object data_and_files (cs, bs, obj), children in List.fold_left install_group_lib_aux data_and_files children in (* Findlib name of the root library *) let findlib_name = findlib_of_group grp in (* Determine root library *) let root_lib = root_of_group grp in (* All files to install for this library *) let f_data, files = install_group_lib_aux (ignore, []) grp in (* Really install, if there is something to install *) if files = [] then begin warning (f_ "Nothing to install for findlib library '%s'") findlib_name end else begin let meta = (* Search META file *) let _, bs, _ = root_lib in let res = Filename.concat bs.bs_path "META" in if not (OASISFileUtil.file_exists_case res) then failwithf (f_ "Cannot find file '%s' for findlib library %s") res findlib_name; res in let files = (* Make filename shorter to avoid hitting command max line length * too early, esp. on Windows. *) let remove_prefix p n = let plen = String.length p in let nlen = String.length n in if plen <= nlen && String.sub n 0 plen = p then begin let fn_sep = if Sys.os_type = "Win32" then '\\' else '/' in let cutpoint = plen + (if plen < nlen && n.[plen] = fn_sep then 1 else 0) in String.sub n cutpoint (nlen - cutpoint) end else n in List.map (remove_prefix (Sys.getcwd ())) files in info (f_ "Installing findlib library '%s'") findlib_name; let ocamlfind = ocamlfind () in let commands = split_install_command ocamlfind findlib_name meta files in List.iter (OASISExec.run ~ctxt:!BaseContext.default ocamlfind) commands; BaseLog.register install_findlib_ev findlib_name end; (* Install data files *) f_data (); in let group_libs, _, _ = findlib_mapping pkg in (* We install libraries in groups *) List.iter install_group_lib group_libs in let install_execs pkg = let install_exec data_exec = let cs, bs, exec = !exec_hook data_exec in if var_choose bs.bs_install && BaseBuilt.is_built BaseBuilt.BExec cs.cs_name then begin let exec_libdir () = Filename.concat (libdir ()) pkg.name in BaseBuilt.fold BaseBuilt.BExec cs.cs_name (fun () fn -> install_file ~tgt_fn:(cs.cs_name ^ ext_program ()) fn bindir) (); BaseBuilt.fold BaseBuilt.BExecLib cs.cs_name (fun () fn -> install_file fn exec_libdir) (); install_data bs.bs_path bs.bs_data_files (Filename.concat (datarootdir ()) pkg.name) end in List.iter (function | Executable (cs, bs, exec)-> install_exec (cs, bs, exec) | _ -> ()) pkg.sections in let install_docs pkg = let install_doc data = let cs, doc = !doc_hook data in if var_choose doc.doc_install && BaseBuilt.is_built BaseBuilt.BDoc cs.cs_name then begin let tgt_dir = OASISHostPath.of_unix (var_expand doc.doc_install_dir) in BaseBuilt.fold BaseBuilt.BDoc cs.cs_name (fun () fn -> install_file fn (fun () -> tgt_dir)) (); install_data Filename.current_dir_name doc.doc_data_files doc.doc_install_dir end in List.iter (function | Doc (cs, doc) -> install_doc (cs, doc) | _ -> ()) pkg.sections in install_libs pkg; install_execs pkg; install_docs pkg (* Uninstall already installed data *) let uninstall _ argv = List.iter (fun (ev, data) -> if ev = install_file_ev then begin if OASISFileUtil.file_exists_case data then begin info (f_ "Removing file '%s'") data; Sys.remove data end else begin warning (f_ "File '%s' doesn't exist anymore") data end end else if ev = install_dir_ev then begin if Sys.file_exists data && Sys.is_directory data then begin if Sys.readdir data = [||] then begin info (f_ "Removing directory '%s'") data; OASISFileUtil.rmdir ~ctxt:!BaseContext.default data end else begin warning (f_ "Directory '%s' is not empty (%s)") data (String.concat ", " (Array.to_list (Sys.readdir data))) end end else begin warning (f_ "Directory '%s' doesn't exist anymore") data end end else if ev = install_findlib_ev then begin info (f_ "Removing findlib library '%s'") data; OASISExec.run ~ctxt:!BaseContext.default (ocamlfind ()) ["remove"; data] end else failwithf (f_ "Unknown log event '%s'") ev; BaseLog.unregister ev data) (* We process event in reverse order *) (List.rev (BaseLog.filter [install_file_ev; install_dir_ev; install_findlib_ev])) end # 6273 "setup.ml" module OCamlbuildCommon = struct (* # 22 "src/plugins/ocamlbuild/OCamlbuildCommon.ml" *) (** Functions common to OCamlbuild build and doc plugin *) open OASISGettext open BaseEnv open BaseStandardVar open OASISTypes type extra_args = string list let ocamlbuild_clean_ev = "ocamlbuild-clean" let ocamlbuildflags = var_define ~short_desc:(fun () -> "OCamlbuild additional flags") "ocamlbuildflags" (fun () -> "") (** Fix special arguments depending on environment *) let fix_args args extra_argv = List.flatten [ if (os_type ()) = "Win32" then [ "-classic-display"; "-no-log"; "-no-links"; "-install-lib-dir"; (Filename.concat (standard_library ()) "ocamlbuild") ] else []; if not (bool_of_string (is_native ())) || (os_type ()) = "Win32" then [ "-byte-plugin" ] else []; args; if bool_of_string (debug ()) then ["-tag"; "debug"] else []; if bool_of_string (tests ()) then ["-tag"; "tests"] else []; if bool_of_string (profile ()) then ["-tag"; "profile"] else []; OASISString.nsplit (ocamlbuildflags ()) ' '; Array.to_list extra_argv; ] (** Run 'ocamlbuild -clean' if not already done *) let run_clean extra_argv = let extra_cli = String.concat " " (Array.to_list extra_argv) in (* Run if never called with these args *) if not (BaseLog.exists ocamlbuild_clean_ev extra_cli) then begin OASISExec.run ~ctxt:!BaseContext.default (ocamlbuild ()) (fix_args ["-clean"] extra_argv); BaseLog.register ocamlbuild_clean_ev extra_cli; at_exit (fun () -> try BaseLog.unregister ocamlbuild_clean_ev extra_cli with _ -> ()) end (** Run ocamlbuild, unregister all clean events *) let run_ocamlbuild args extra_argv = (* TODO: enforce that target in args must be UNIX encoded i.e. toto/index.html *) OASISExec.run ~ctxt:!BaseContext.default (ocamlbuild ()) (fix_args args extra_argv); (* Remove any clean event, we must run it again *) List.iter (fun (e, d) -> BaseLog.unregister e d) (BaseLog.filter [ocamlbuild_clean_ev]) (** Determine real build directory *) let build_dir extra_argv = let rec search_args dir = function | "-build-dir" :: dir :: tl -> search_args dir tl | _ :: tl -> search_args dir tl | [] -> dir in search_args "_build" (fix_args [] extra_argv) end module OCamlbuildPlugin = struct (* # 22 "src/plugins/ocamlbuild/OCamlbuildPlugin.ml" *) (** Build using ocamlbuild @author Sylvain Le Gall *) open OASISTypes open OASISGettext open OASISUtils open OASISString open BaseEnv open OCamlbuildCommon open BaseStandardVar open BaseMessage let cond_targets_hook = ref (fun lst -> lst) let build extra_args pkg argv = (* Return the filename in build directory *) let in_build_dir fn = Filename.concat (build_dir argv) fn in (* Return the unix filename in host build directory *) let in_build_dir_of_unix fn = in_build_dir (OASISHostPath.of_unix fn) in let cond_targets = List.fold_left (fun acc -> function | Library (cs, bs, lib) when var_choose bs.bs_build -> begin let evs, unix_files = BaseBuilt.of_library in_build_dir_of_unix (cs, bs, lib) in let tgts = List.flatten (List.filter (fun l -> l <> []) (List.map (List.filter (fun fn -> ends_with ~what:".cma" fn || ends_with ~what:".cmxs" fn || ends_with ~what:".cmxa" fn || ends_with ~what:(ext_lib ()) fn || ends_with ~what:(ext_dll ()) fn)) unix_files)) in match tgts with | _ :: _ -> (evs, tgts) :: acc | [] -> failwithf (f_ "No possible ocamlbuild targets for library %s") cs.cs_name end | Object (cs, bs, obj) when var_choose bs.bs_build -> begin let evs, unix_files = BaseBuilt.of_object in_build_dir_of_unix (cs, bs, obj) in let tgts = List.flatten (List.filter (fun l -> l <> []) (List.map (List.filter (fun fn -> ends_with ".cmo" fn || ends_with ".cmx" fn)) unix_files)) in match tgts with | _ :: _ -> (evs, tgts) :: acc | [] -> failwithf (f_ "No possible ocamlbuild targets for object %s") cs.cs_name end | Executable (cs, bs, exec) when var_choose bs.bs_build -> begin let evs, unix_exec_is, unix_dll_opt = BaseBuilt.of_executable in_build_dir_of_unix (cs, bs, exec) in let target ext = let unix_tgt = (OASISUnixPath.concat bs.bs_path (OASISUnixPath.chop_extension exec.exec_main_is))^ext in let evs = (* Fix evs, we want to use the unix_tgt, without copying *) List.map (function | BaseBuilt.BExec, nm, lst when nm = cs.cs_name -> BaseBuilt.BExec, nm, [[in_build_dir_of_unix unix_tgt]] | ev -> ev) evs in evs, [unix_tgt] in (* Add executable *) let acc = match bs.bs_compiled_object with | Native -> (target ".native") :: acc | Best when bool_of_string (is_native ()) -> (target ".native") :: acc | Byte | Best -> (target ".byte") :: acc in acc end | Library _ | Object _ | Executable _ | Test _ | SrcRepo _ | Flag _ | Doc _ -> acc) [] (* Keep the pkg.sections ordered *) (List.rev pkg.sections); in (* Check and register built files *) let check_and_register (bt, bnm, lst) = List.iter (fun fns -> if not (List.exists OASISFileUtil.file_exists_case fns) then failwithf (fn_ "Expected built file %s doesn't exist." "None of expected built files %s exists." (List.length fns)) (String.concat (s_ " or ") (List.map (Printf.sprintf "'%s'") fns))) lst; (BaseBuilt.register bt bnm lst) in (* Run the hook *) let cond_targets = !cond_targets_hook cond_targets in (* Run a list of target... *) run_ocamlbuild (List.flatten (List.map snd cond_targets) @ extra_args) argv; (* ... and register events *) List.iter check_and_register (List.flatten (List.map fst cond_targets)) let clean pkg extra_args = run_clean extra_args; List.iter (function | Library (cs, _, _) -> BaseBuilt.unregister BaseBuilt.BLib cs.cs_name | Executable (cs, _, _) -> BaseBuilt.unregister BaseBuilt.BExec cs.cs_name; BaseBuilt.unregister BaseBuilt.BExecLib cs.cs_name | _ -> ()) pkg.sections end module OCamlbuildDocPlugin = struct (* # 22 "src/plugins/ocamlbuild/OCamlbuildDocPlugin.ml" *) (* Create documentation using ocamlbuild .odocl files @author Sylvain Le Gall *) open OASISTypes open OASISGettext open OASISMessage open OCamlbuildCommon open BaseStandardVar type run_t = { extra_args: string list; run_path: unix_filename; } let doc_build run pkg (cs, doc) argv = let index_html = OASISUnixPath.make [ run.run_path; cs.cs_name^".docdir"; "index.html"; ] in let tgt_dir = OASISHostPath.make [ build_dir argv; OASISHostPath.of_unix run.run_path; cs.cs_name^".docdir"; ] in run_ocamlbuild (index_html :: run.extra_args) argv; List.iter (fun glb -> BaseBuilt.register BaseBuilt.BDoc cs.cs_name [OASISFileUtil.glob ~ctxt:!BaseContext.default (Filename.concat tgt_dir glb)]) ["*.html"; "*.css"] let doc_clean run pkg (cs, doc) argv = run_clean argv; BaseBuilt.unregister BaseBuilt.BDoc cs.cs_name end # 6651 "setup.ml" module CustomPlugin = struct (* # 22 "src/plugins/custom/CustomPlugin.ml" *) (** Generate custom configure/build/doc/test/install system @author *) open BaseEnv open OASISGettext open OASISTypes type t = { cmd_main: command_line conditional; cmd_clean: (command_line option) conditional; cmd_distclean: (command_line option) conditional; } let run = BaseCustom.run let main t _ extra_args = let cmd, args = var_choose ~name:(s_ "main command") t.cmd_main in run cmd args extra_args let clean t pkg extra_args = match var_choose t.cmd_clean with | Some (cmd, args) -> run cmd args extra_args | _ -> () let distclean t pkg extra_args = match var_choose t.cmd_distclean with | Some (cmd, args) -> run cmd args extra_args | _ -> () module Build = struct let main t pkg extra_args = main t pkg extra_args; List.iter (fun sct -> let evs = match sct with | Library (cs, bs, lib) when var_choose bs.bs_build -> begin let evs, _ = BaseBuilt.of_library OASISHostPath.of_unix (cs, bs, lib) in evs end | Executable (cs, bs, exec) when var_choose bs.bs_build -> begin let evs, _, _ = BaseBuilt.of_executable OASISHostPath.of_unix (cs, bs, exec) in evs end | _ -> [] in List.iter (fun (bt, bnm, lst) -> BaseBuilt.register bt bnm lst) evs) pkg.sections let clean t pkg extra_args = clean t pkg extra_args; (* TODO: this seems to be pretty generic (at least wrt to ocamlbuild * considering moving this to BaseSetup? *) List.iter (function | Library (cs, _, _) -> BaseBuilt.unregister BaseBuilt.BLib cs.cs_name | Executable (cs, _, _) -> BaseBuilt.unregister BaseBuilt.BExec cs.cs_name; BaseBuilt.unregister BaseBuilt.BExecLib cs.cs_name | _ -> ()) pkg.sections let distclean t pkg extra_args = distclean t pkg extra_args end module Test = struct let main t pkg (cs, test) extra_args = try main t pkg extra_args; 0.0 with Failure s -> BaseMessage.warning (f_ "Test '%s' fails: %s") cs.cs_name s; 1.0 let clean t pkg (cs, test) extra_args = clean t pkg extra_args let distclean t pkg (cs, test) extra_args = distclean t pkg extra_args end module Doc = struct let main t pkg (cs, _) extra_args = main t pkg extra_args; BaseBuilt.register BaseBuilt.BDoc cs.cs_name [] let clean t pkg (cs, _) extra_args = clean t pkg extra_args; BaseBuilt.unregister BaseBuilt.BDoc cs.cs_name let distclean t pkg (cs, _) extra_args = distclean t pkg extra_args end end # 6799 "setup.ml" open OASISTypes;; let setup_t = { BaseSetup.configure = InternalConfigurePlugin.configure; build = OCamlbuildPlugin.build ["-use-ocamlfind"]; test = [ ("test_runner", CustomPlugin.Test.main { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("$test_runner", []))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }) ]; doc = []; install = InternalInstallPlugin.install; uninstall = InternalInstallPlugin.uninstall; clean = [OCamlbuildPlugin.clean]; clean_test = [ ("test_runner", CustomPlugin.Test.clean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("$test_runner", []))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }) ]; clean_doc = []; distclean = []; distclean_test = [ ("test_runner", CustomPlugin.Test.distclean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("$test_runner", []))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }) ]; distclean_doc = []; package = { oasis_version = "0.3"; ocaml_version = Some (OASISVersion.VGreaterEqual "4.00.1"); findlib_version = Some (OASISVersion.VGreaterEqual "1.3.2"); alpha_features = []; beta_features = []; name = "core"; version = "113.00.00"; license = OASISLicense.DEP5License (OASISLicense.DEP5Unit { OASISLicense.license = "Apache"; excption = None; version = OASISLicense.Version "2.0" }); license_file = Some "LICENSE.txt"; copyrights = [ "(C) 2008-2013 Jane Street Group LLC " ]; maintainers = ["Jane Street Group"; "LLC "]; authors = ["Jane Street Group"; "LLC "]; homepage = Some "https://github.com/janestreet/core"; synopsis = "Jane Street Capital's standard library overlay"; description = Some [ OASISText.Para "The Core suite of libraries is an industrial strength alternative to OCaml's standard library that was developed by Jane Street, the largest industrial user of OCaml." ]; categories = []; conf_type = (`Configure, "internal", Some "0.4"); conf_custom = { pre_command = [(OASISExpr.EBool true, Some (("config/detect.sh", [])))]; post_command = [ (OASISExpr.EBool true, Some (("config/discover.sh", [ "$ocamlc"; "src/core_config.mlh"; "src/core_config.h" ]))) ] }; build_type = (`Build, "ocamlbuild", Some "0.4"); build_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; install_type = (`Install, "internal", Some "0.4"); install_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; uninstall_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; clean_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; distclean_custom = { pre_command = [ (OASISExpr.EBool true, Some (("$rm", ["src/core_config.mlh"; "src/core_config.h"]))) ]; post_command = [(OASISExpr.EBool true, None)] }; files_ab = []; sections = [ Flag ({ cs_name = "linux"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { flag_description = Some "Enable linux specific extensions"; flag_default = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "linux_possible", true) ] }); Flag ({ cs_name = "posix-timers"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { flag_description = Some "Enable POSIX timers"; flag_default = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "posix_timers_possible", true) ] }); Flag ({ cs_name = "rt"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { flag_description = Some "Linux RT Library"; flag_default = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "rt_possible", true) ] }); Library ({ cs_name = "core"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [(OASISExpr.EBool true, true)]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src"; bs_compiled_object = Best; bs_build_depends = [ FindlibPackage ("bigarray", None); FindlibPackage ("bin_prot", None); FindlibPackage ("bin_prot.syntax", None); FindlibPackage ("comparelib.syntax", None); FindlibPackage ("core_kernel", None); FindlibPackage ("custom_printf", None); FindlibPackage ("custom_printf.syntax", None); FindlibPackage ("enumerate.syntax", None); FindlibPackage ("fieldslib", None); FindlibPackage ("fieldslib.syntax", None); FindlibPackage ("herelib", None); FindlibPackage ("herelib.syntax", None); FindlibPackage ("pa_bench", None); FindlibPackage ("pa_bench.syntax", None); FindlibPackage ("pa_ounit", None); FindlibPackage ("pa_ounit.syntax", None); FindlibPackage ("pa_pipebang", None); FindlibPackage ("pa_structural_sexp", None); FindlibPackage ("pa_structural_sexp.syntax", None); FindlibPackage ("pa_test", None); FindlibPackage ("pa_test.syntax", None); FindlibPackage ("sexplib", None); FindlibPackage ("sexplib.syntax", None); FindlibPackage ("sexplib_unix", None); FindlibPackage ("typerep_lib", None); FindlibPackage ("typerep_lib.syntax", None); FindlibPackage ("unix", None); FindlibPackage ("variantslib", None); FindlibPackage ("variantslib.syntax", None); FindlibPackage ("threads", None) ]; bs_build_tools = [ExternalTool "ocamlbuild"; ExternalTool "camlp4o"]; bs_c_sources = [ "bigstring_stubs.c"; "crc_stubs.c"; "includes.h"; "iobuf.h"; "iobuf_stubs.c"; "jane_common.h"; "linux_ext_stubs.c"; "nanosecond_stat.h"; "ocaml_utils.h"; "ocaml_utils_macros.h"; "ocaml_utils_stubs.c"; "recvmmsg.c"; "recvmmsg.h"; "signal_stubs.c"; "socketaddr.h"; "syslog_stubs.c"; "timespec.c"; "timespec.h"; "time_ns_stubs.c"; "time_stamp_counter_stubs.c"; "unix_stubs.c"; "unix_time_stubs.c"; "unix_utils.h"; "core_config.h" ]; bs_data_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [ (OASISExpr.EBool true, []); (OASISExpr.EFlag "rt", ["-lrt"]) ]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = [ "Bigbuffer"; "Bigstring_marshal"; "Bigstring"; "Caml"; "Check_std"; "Command"; "Core_condition"; "Core_filename"; "Core_list"; "Core_mutex"; "Core_sys"; "Core_thread"; "Core_unix"; "Crc"; "Daemon"; "Date0"; "Date"; "Debug"; "Interval_intf"; "Interval"; "Iobuf_debug"; "Iobuf_intf"; "Iobuf"; "Iobuf_tests"; "Limiter"; "Limiter_unit_tests"; "Linux_ext"; "Lock_file"; "Mutex0"; "Nano_mutex"; "Ofday"; "Piecewise_linear_intf"; "Piecewise_linear"; "Process_env"; "Signal"; "Span"; "Squeue"; "Stable"; "Std"; "Syscall_result_intf"; "Syscall_result"; "Syslog"; "Thread_safe_queue_unit_tests"; "Time0"; "Time_internal"; "Time"; "Time_ns_benchmarks"; "Time_ns"; "Time_stamp_counter"; "Time_stamp_counter_benchmarks"; "Timing_wheel_float"; "Timing_wheel_float_unit_tests"; "Unix_error"; "User_and_group"; "Uuid"; "Weak_hashtbl"; "Zone"; "Array_permute"; "Avltree"; "Bag"; "Bigbuffer_internal"; "Bigsubstring"; "Binable"; "Binable0"; "Binary_packing"; "Blang"; "Bool"; "Bounded_int_table"; "Bucket"; "Byte_units"; "Commutative_group"; "Comparable"; "Comparable_intf"; "Comparator"; "Constrained_float"; "Container"; "Core_arg"; "Core_array"; "Core_bin_prot"; "Core_char"; "Core_field"; "Core_hashtbl"; "Core_hashtbl_intf"; "Core_int"; "Core_int32"; "Core_int63"; "Core_int64"; "Core_lazy"; "Core_map"; "Core_map_intf"; "Core_map_unit_tests"; "Core_nativeint"; "Core_printexc"; "Core_printf"; "Core_random"; "Core_set"; "Core_set_intf"; "Core_set_unit_tests"; "Core_sexp"; "Core_stack"; "Core_string"; "Day_of_week"; "Dequeue"; "Doubly_linked"; "Equal"; "Error"; "Exn"; "Flags"; "Flags_intf"; "Float"; "Float_intf"; "Float_robust_compare"; "Floatable"; "Fn"; "Force_once"; "Fqueue"; "Hash_heap"; "Hash_queue"; "Hash_set"; "Hash_set_intf"; "Hashable"; "Heap"; "Heap_block"; "Host_and_port"; "Identifiable"; "In_channel"; "Info"; "Int_conversions"; "Int_intf"; "Int_replace_polymorphic_compare"; "Int_set"; "Intable"; "Interfaces"; "Invariant"; "Make_substring"; "Memo"; "Monad"; "Month"; "Never_returns"; "No_polymorphic_compare"; "Nothing"; "Nothing0"; "Only_in_test"; "Option"; "Or_error"; "Ordered_collection_common"; "Ordering"; "Out_channel"; "Pid"; "Polymorphic_compare"; "Polymorphic_compare_intf"; "Pretty_printer"; "Ref"; "Result"; "Robustly_comparable"; "Set_once"; "Sexpable"; "Source_code_position"; "Source_code_position0"; "Stable_containers"; "Stable_internal"; "Stable_unit_test"; "Stable_unit_test_intf"; "Staged"; "Std_common"; "Std_internal"; "Std_kernel"; "String_id"; "Stringable"; "Substring"; "Substring_intf"; "T"; "Tuple"; "Type_equal"; "Union_find"; "Unique_id"; "Unique_id_intf"; "Unit"; "Univ"; "Univ_map"; "Unpack_buffer"; "Validate"; "Word_size" ]; lib_pack = true; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = Some "core"; lib_findlib_containers = [] }); Library ({ cs_name = "core_top"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [(OASISExpr.EBool true, true)]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "top"; bs_compiled_object = Best; bs_build_depends = [ InternalLibrary "core"; FindlibPackage ("compiler-libs", None) ]; bs_build_tools = [ExternalTool "ocamlbuild"; ExternalTool "camlp4o"]; bs_c_sources = []; bs_data_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = ["Core_install_printers"]; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = Some "core"; lib_findlib_name = Some "top"; lib_findlib_containers = [] }); Executable ({ cs_name = "test_runner"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "tests", true) ]; bs_install = [(OASISExpr.EBool true, false)]; bs_path = "test"; bs_compiled_object = Best; bs_build_depends = [ InternalLibrary "core"; FindlibPackage ("oUnit", Some (OASISVersion.VGreaterEqual "1.0.2")) ]; bs_build_tools = [ExternalTool "ocamlbuild"; ExternalTool "camlp4o"]; bs_c_sources = []; bs_data_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, {exec_custom = true; exec_main_is = "test_runner.ml"}); Test ({ cs_name = "test_runner"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { test_type = (`Test, "custom", Some "0.4"); test_command = [(OASISExpr.EBool true, ("$test_runner", []))]; test_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; test_working_directory = Some "test"; test_run = [ (OASISExpr.ENot (OASISExpr.EFlag "tests"), false); (OASISExpr.EFlag "tests", false); (OASISExpr.EAnd (OASISExpr.EFlag "tests", OASISExpr.EFlag "tests"), true) ]; test_tools = [ExternalTool "ocamlbuild"; ExternalTool "camlp4o"] }) ]; plugins = [ (`Extra, "StdFiles", Some "0.3"); (`Extra, "DevFiles", Some "0.3"); (`Extra, "META", Some "0.3") ]; disable_oasis_section = []; schema_data = PropList.Data.create (); plugin_data = [] }; oasis_fn = Some "_oasis"; oasis_version = "0.4.5"; oasis_digest = Some "Cu*t\218\012\214g\130\165+\1765\005@>"; oasis_exec = None; oasis_setup_args = []; setup_update = false };; let setup () = BaseSetup.setup setup_t;; # 7373 "setup.ml" (* OASIS_STOP *) let () = InternalInstallPlugin.lib_hook := fun (cs, bs, lib) -> match lib.OASISTypes.lib_findlib_name with | Some "core" -> (cs, bs, lib, [ "src/ocaml_utils_macros.h"; "src/ocaml_utils.h"; "src/unix_utils.h"; "src/core_config.h"; "src/jane_common.h"]) | _ -> (cs, bs, lib, []) ;; let () = setup () core-113.00.00/src/000077500000000000000000000000001256461075500135465ustar00rootroot00000000000000core-113.00.00/src/META000066400000000000000000000022321256461075500142160ustar00rootroot00000000000000# OASIS_START # DO NOT EDIT (digest: 2738c03b9030acca792d96f883a1ca8a) version = "113.00.00" description = "Jane Street Capital's standard library overlay" requires = "bin_prot core_kernel custom_printf variantslib sexplib sexplib_unix enumerate fieldslib bigarray pa_bench pa_ounit pa_structural_sexp pa_test unix threads typerep_lib" archive(byte) = "core.cma" archive(byte, plugin) = "core.cma" archive(native) = "core.cmxa" archive(native, plugin) = "core.cmxs" archive(byte, toploop) += "core_top.cma" archive(native, toploop) += "core_top.cmxa" exists_if = "core.cma" package "top" ( version = "113.00.00" description = "Toplevel printers for Core" requires = "core" archive(byte) = "core_top.cma" archive(byte, plugin) = "core_top.cma" archive(native) = "core_top.cmxa" archive(native, plugin) = "core_top.cmxs" exists_if = "core_top.cma" ) # OASIS_STOP package "syntax" ( version = "109.32.00" description = "Metapackage for syntax extensions of the Core suite" requires = "sexplib.syntax fieldslib.syntax variantslib.syntax comparelib.syntax bin_prot.syntax custom_printf.syntax pa_pipebang herelib.syntax" archive(syntax, preprocessor) = "-ignore dummy" ) core-113.00.00/src/array_permute.ml000066400000000000000000000000421256461075500167530ustar00rootroot00000000000000include Core_kernel.Array_permute core-113.00.00/src/avltree.ml000066400000000000000000000000341256461075500155370ustar00rootroot00000000000000include Core_kernel.Avltree core-113.00.00/src/bag.ml000066400000000000000000000000301256461075500146220ustar00rootroot00000000000000include Core_kernel.Bag core-113.00.00/src/bigbuffer.ml000066400000000000000000000006721256461075500160400ustar00rootroot00000000000000include Core_kernel.Std.Bigbuffer open Core_kernel.Bigbuffer_internal let add_channel buf ic len = let buf = __internal buf in if len < 0 then invalid_arg "Bigbuffer.add_channel"; let pos = buf.pos in if pos + len > buf.len then resize buf len; Bigstring.really_input ic buf.bstr ~pos ~len; buf.pos <- pos + len; ;; let output_buffer oc buf = let buf = __internal buf in Bigstring.really_output oc buf.bstr ~len:buf.pos ;; core-113.00.00/src/bigbuffer.mli000066400000000000000000000010041256461075500161770ustar00rootroot00000000000000open Core_kernel.Std include module type of Core_kernel.Std.Bigbuffer with type t = Core_kernel.Std.Bigbuffer.t val add_channel : t -> in_channel -> int -> unit (** [add_channel b ic n] reads exactly [n] character from the input channel [ic] and stores them at the end of buffer [b]. Raise [End_of_file] if the channel contains fewer than [n] characters. *) val output_buffer : out_channel -> t -> unit (** [output_buffer oc b] writes the current contents of buffer [b] on the output channel [oc]. *) core-113.00.00/src/bigbuffer_internal.ml000066400000000000000000000000471256461075500177300ustar00rootroot00000000000000include Core_kernel.Bigbuffer_internal core-113.00.00/src/bigstring.ml000066400000000000000000000342271256461075500161000ustar00rootroot00000000000000INCLUDE "core_config.mlh" open Core_kernel.Std open Unix open Bigarray open Sexplib.Std include Core_kernel.Std.Bigstring exception IOError of int * exn with sexp external init : unit -> unit = "bigstring_init_stub" let () = Callback.register_exception "Bigstring.End_of_file" End_of_file; Callback.register_exception "Bigstring.IOError" (IOError (0, Exit)); init () external aux_create: max_mem_waiting_gc:int -> size:int -> t = "bigstring_alloc" let create ?max_mem_waiting_gc size = let max_mem_waiting_gc = match max_mem_waiting_gc with | None -> ~-1 | Some v -> Float.to_int (Byte_units.bytes v) in if size < 0 then invalid_argf "create: size = %d < 0" size (); aux_create ~max_mem_waiting_gc ~size let length = Array1.dim external is_mmapped : t -> bool = "bigstring_is_mmapped_stub" "noalloc" let init n ~f = let t = create n in for i = 0 to n - 1; do t.{i} <- f i; done; t ;; let check_args ~loc ~pos ~len (bstr : t) = if pos < 0 then invalid_arg (loc ^ ": pos < 0"); if len < 0 then invalid_arg (loc ^ ": len < 0"); let bstr_len = length bstr in if bstr_len < pos + len then invalid_arg (sprintf "Bigstring.%s: length(bstr) < pos + len" loc) let get_opt_len bstr ~pos = function | Some len -> len | None -> length bstr - pos let check_min_len ~loc ~len = function | None -> 0 | Some min_len -> if min_len > len then ( let msg = sprintf "%s: min_len (%d) > len (%d)" loc min_len len in invalid_arg msg); if min_len < 0 then ( let msg = sprintf "%s: min_len (%d) < 0" loc min_len in invalid_arg msg); min_len let sub_shared ?(pos = 0) ?len (bstr : t) = let len = get_opt_len bstr ~pos len in Array1.sub bstr pos len (* Input functions *) external unsafe_read : min_len : int -> file_descr -> pos : int -> len : int -> t -> int = "bigstring_read_stub" let read ?min_len fd ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in let loc = "read" in check_args ~loc ~pos ~len bstr; let min_len = check_min_len ~loc ~len min_len in unsafe_read ~min_len fd ~pos ~len bstr external unsafe_pread_assume_fd_is_nonblocking_stub : file_descr -> offset : int -> pos : int -> len : int -> t -> int = "bigstring_pread_assume_fd_is_nonblocking_stub" let pread_assume_fd_is_nonblocking fd ~offset ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in let loc = "pread" in check_args ~loc ~pos ~len bstr; unsafe_pread_assume_fd_is_nonblocking_stub fd ~offset ~pos ~len bstr let really_read fd ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in ignore (read ~min_len:len fd ~pos ~len bstr) external unsafe_really_recv : file_descr -> pos : int -> len : int -> t -> unit = "bigstring_really_recv_stub" let really_recv sock ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"really_recv" ~pos ~len bstr; unsafe_really_recv sock ~pos ~len bstr external unsafe_recvfrom_assume_fd_is_nonblocking : file_descr -> pos : int -> len : int -> t -> int * sockaddr = "bigstring_recvfrom_assume_fd_is_nonblocking_stub" let recvfrom_assume_fd_is_nonblocking sock ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"recvfrom_assume_fd_is_nonblocking" ~pos ~len bstr; unsafe_recvfrom_assume_fd_is_nonblocking sock ~pos ~len bstr external unsafe_read_assume_fd_is_nonblocking : file_descr -> pos : int -> len : int -> t -> Syscall_result.Int.t = "bigstring_read_assume_fd_is_nonblocking_stub" let read_assume_fd_is_nonblocking fd ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"read_assume_fd_is_nonblocking" ~pos ~len bstr; unsafe_read_assume_fd_is_nonblocking fd ~pos ~len bstr external unsafe_input : min_len : int -> in_channel -> pos : int -> len : int -> t -> int = "bigstring_input_stub" let input ?min_len ic ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in let loc = "input" in check_args ~loc ~pos ~len bstr; let min_len = check_min_len ~loc ~len min_len in unsafe_input ~min_len ic ~pos ~len bstr let really_input ic ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"really_input" ~pos ~len bstr; ignore (unsafe_input ~min_len:len ic ~pos ~len bstr) (* Output functions *) external unsafe_really_write : file_descr -> pos : int -> len : int -> t -> unit = "bigstring_really_write_stub" let really_write fd ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"really_write" ~pos ~len bstr; unsafe_really_write fd ~pos ~len bstr external unsafe_pwrite_assume_fd_is_nonblocking : file_descr -> offset : int -> pos : int -> len : int -> t -> int = "bigstring_pwrite_assume_fd_is_nonblocking_stub" let pwrite_assume_fd_is_nonblocking fd ~offset ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in let loc = "pwrite" in check_args ~loc ~pos ~len bstr; unsafe_pwrite_assume_fd_is_nonblocking fd ~offset ~pos ~len bstr IFDEF MSG_NOSIGNAL THEN external unsafe_really_send_no_sigpipe : file_descr -> pos : int -> len : int -> t -> unit = "bigstring_really_send_no_sigpipe_stub" let really_send_no_sigpipe fd ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"really_send_no_sigpipe" ~pos ~len bstr; unsafe_really_send_no_sigpipe fd ~pos ~len bstr external unsafe_send_nonblocking_no_sigpipe : file_descr -> pos : int -> len : int -> t -> Syscall_result.Int.t = "bigstring_send_nonblocking_no_sigpipe_stub" "noalloc" let send_nonblocking_no_sigpipe fd ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"send_nonblocking_no_sigpipe" ~pos ~len bstr; unsafe_send_nonblocking_no_sigpipe fd ~pos ~len bstr external unsafe_sendto_nonblocking_no_sigpipe : file_descr -> pos : int -> len : int -> t -> sockaddr -> Syscall_result.Int.t = "bigstring_sendto_nonblocking_no_sigpipe_stub" let sendto_nonblocking_no_sigpipe fd ?(pos = 0) ?len bstr sockaddr = let len = get_opt_len bstr ~pos len in check_args ~loc:"sendto_nonblocking_no_sigpipe" ~pos ~len bstr; unsafe_sendto_nonblocking_no_sigpipe fd ~pos ~len bstr sockaddr let really_send_no_sigpipe = Ok really_send_no_sigpipe let send_nonblocking_no_sigpipe = Ok send_nonblocking_no_sigpipe let sendto_nonblocking_no_sigpipe = Ok sendto_nonblocking_no_sigpipe let unsafe_really_send_no_sigpipe = Ok unsafe_really_send_no_sigpipe let unsafe_send_nonblocking_no_sigpipe = Ok unsafe_send_nonblocking_no_sigpipe ELSE let u = Or_error.unimplemented let really_send_no_sigpipe = u "Bigstring.really_send_no_sigpipe" let send_nonblocking_no_sigpipe = u "Bigstring.send_nonblocking_no_sigpipe" let sendto_nonblocking_no_sigpipe = u "Bigstring.sendto_nonblocking_no_sigpipe" let unsafe_really_send_no_sigpipe = u "Bigstring.unsafe_really_send_no_sigpipe" let unsafe_send_nonblocking_no_sigpipe = u "Bigstring.unsafe_send_nonblocking_no_sigpipe" ENDIF external unsafe_write : file_descr -> pos : int -> len : int -> t -> int = "bigstring_write_stub" let write fd ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"write" ~pos ~len bstr; unsafe_write fd ~pos ~len bstr external unsafe_write_assume_fd_is_nonblocking : file_descr -> pos : int -> len : int -> t -> int = "bigstring_write_assume_fd_is_nonblocking_stub" let write_assume_fd_is_nonblocking fd ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"write_assume_fd_is_nonblocking" ~pos ~len bstr; unsafe_write_assume_fd_is_nonblocking fd ~pos ~len bstr external unsafe_writev : file_descr -> t Core_unix.IOVec.t array -> int -> int = "bigstring_writev_stub" let get_iovec_count loc iovecs = function | None -> Array.length iovecs | Some count -> if count < 0 then invalid_arg (loc ^ ": count < 0"); let n_iovecs = Array.length iovecs in if count > n_iovecs then invalid_arg (loc ^ ": count > n_iovecs"); count let writev fd ?count iovecs = let count = get_iovec_count "writev" iovecs count in unsafe_writev fd iovecs count external unsafe_writev_assume_fd_is_nonblocking : file_descr -> t Core_unix.IOVec.t array -> int -> int = "bigstring_writev_assume_fd_is_nonblocking_stub" let writev_assume_fd_is_nonblocking fd ?count iovecs = let count = get_iovec_count "writev_nonblocking" iovecs count in unsafe_writev_assume_fd_is_nonblocking fd iovecs count ;; external unsafe_output : min_len : int -> out_channel -> pos : int -> len : int -> t -> int = "bigstring_output_stub" let output ?min_len oc ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in let loc = "output" in check_args ~loc ~pos ~len bstr; let min_len = check_min_len ~loc ~len min_len in unsafe_output oc ~min_len ~pos ~len bstr let really_output oc ?(pos = 0) ?len bstr = let len = get_opt_len bstr ~pos len in check_args ~loc:"really_output" ~pos ~len bstr; ignore (unsafe_output oc ~min_len:len ~pos ~len bstr) IFDEF RECVMMSG THEN external unsafe_recvmmsg_assume_fd_is_nonblocking : file_descr -> t Core_unix.IOVec.t array -> int -> sockaddr array option -> int array -> int = "bigstring_recvmmsg_assume_fd_is_nonblocking_stub" TEST_MODULE = struct let expect_invalid_argument ?msg f = assert (try ignore (f () : int); false with Invalid_argument s -> match msg with | None -> true | Some x when String.equal x s -> true | Some x -> failwithf "expected %S but got %S" x s ()) ;; let check_invalid ?msg count = let fd = Core_unix.socket ~domain:PF_INET ~kind:SOCK_DGRAM ~protocol:0 in expect_invalid_argument ?msg (fun () -> unsafe_recvmmsg_assume_fd_is_nonblocking fd [||] count None [||]) TEST_UNIT "unsafe_recvmmsg_assume_fd_is_nonblocking: check count bounds" = check_invalid (-1); check_invalid Int.min_value; check_invalid 65; (* RECVMMSG_MAX_COUNT = 64 *) ( IFDEF ARCH_SIXTYFOUR THEN (* We are assuming that [unsigned int] is 32 bits wide. *) check_invalid (Int64.to_int_exn 0xFFFF_FFFFL); (* exceeds RECVMMSG_MAX_COUNT *) check_invalid (Int64.to_int_exn 0x1FFFF_FFFFL); (* exceeds unsigned int *) ENDIF ) ;; end let recvmmsg_assume_fd_is_nonblocking fd ?count ?srcs iovecs ~lens = let loc = "recvmmsg_assume_fd_is_nonblocking" in let count = get_iovec_count loc iovecs count in begin match srcs with | None -> () | Some a -> if count > Array.length a then invalid_arg (loc ^ ": count > n_srcs") end; if count > Array.length lens then invalid_arg (loc ^ ": count > n_lens"); unsafe_recvmmsg_assume_fd_is_nonblocking fd iovecs count srcs lens ;; TEST_MODULE "recvmmsg smoke" = struct module IOVec = Core_unix.IOVec module Inet_addr = Core_unix.Inet_addr let count = 10 let fd = socket PF_INET SOCK_DGRAM 0 let () = bind fd (ADDR_INET (Inet_addr.bind_any, 0)) let iovecs = Array.init count ~f:(fun _ -> IOVec.of_bigstring (create 1500)) let srcs = Array.create ~len:count (ADDR_INET (Inet_addr.bind_any, 0)) let lens = Array.create ~len:count 0 let short_srcs = Array.create ~len:(count - 1) (ADDR_INET (Inet_addr.bind_any, 0)) let () = set_nonblock fd let test ?count ?srcs ~lens ok_pred error_pred = <:test_pred< (int, exn) Result.t >> (function Ok i -> ok_pred i | Error e -> error_pred e) (Result.try_with (fun () -> recvmmsg_assume_fd_is_nonblocking fd iovecs ?count ?srcs ~lens) ) (* We return -EAGAIN and -EWOULDBLOCK directly as values, rather than as exceptions. So, allow negative results. *) TEST_UNIT = test ~count ~srcs ~lens ((>=) 0) (function Unix_error _ -> true | _ -> false) TEST_UNIT = test ~lens ((>=) 0) (function Unix_error _ -> true | _ -> false) TEST_UNIT = test ~count:(count / 2) ~srcs ~lens ((>=) 0) (function Unix_error _ -> true | _ -> false) TEST_UNIT = test ~count:0 ~srcs ~lens ((>=) 0) (function Unix_error _ -> true | _ -> false) TEST_UNIT = test ~count:(count + 1) ~lens (const false) (function Unix_error _ -> false | _ -> true) TEST_UNIT = test ~srcs:short_srcs ~lens (const false) (function Unix_error _ -> false | _ -> true) end ;; let recvmmsg_assume_fd_is_nonblocking = (* At Jane Street, we link with [--wrap recvmmsg] so that we can use our own wrapper around [recvmmsg]. This allows us to compile an executable on a machine that has recvmmsg (e.g., CentOS 6) but then run the executable on a machine that does not (e.g., CentOS 5), but that has our wrapper library. We set up our wrapper so that when running on a machine that doesn't have it, [recvmmsg] always returns -1 and sets errno to ENOSYS. *) let ok = Ok recvmmsg_assume_fd_is_nonblocking in try assert (recvmmsg_assume_fd_is_nonblocking (Core_unix.File_descr.of_int (-1)) [||] ~lens:[||] = 0); ok (* maybe it will ignore the bogus sockfd *) with | Unix_error (ENOSYS, _, _) -> Or_error.unimplemented "Bigstring.recvmmsg_assume_fd_is_nonblocking" | _ -> ok ;; ELSE (* NDEF RECVMMSG *) let recvmmsg_assume_fd_is_nonblocking = Or_error.unimplemented "Bigstring.recvmmsg_assume_fd_is_nonblocking" ;; ENDIF (* RECVMMSG *) (* Memory mapping *) IFDEF MSG_NOSIGNAL THEN (* Input and output, linux only *) external unsafe_sendmsg_nonblocking_no_sigpipe : file_descr -> t Core_unix.IOVec.t array -> int -> int = "bigstring_sendmsg_nonblocking_no_sigpipe_stub" let unsafe_sendmsg_nonblocking_no_sigpipe fd iovecs count = let res = unsafe_sendmsg_nonblocking_no_sigpipe fd iovecs count in if res = -1 then None else Some res let sendmsg_nonblocking_no_sigpipe fd ?count iovecs = let count = get_iovec_count "sendmsg_nonblocking_no_sigpipe" iovecs count in unsafe_sendmsg_nonblocking_no_sigpipe fd iovecs count let sendmsg_nonblocking_no_sigpipe = Ok sendmsg_nonblocking_no_sigpipe let unsafe_sendmsg_nonblocking_no_sigpipe = Ok unsafe_sendmsg_nonblocking_no_sigpipe ELSE let sendmsg_nonblocking_no_sigpipe = Or_error.unimplemented "Bigstring.sendmsg_nonblocking_no_sigpipe" ;; let unsafe_sendmsg_nonblocking_no_sigpipe = Or_error.unimplemented "Bigstring.unsafe_sendmsg_nonblocking_no_sigpipe" ;; ENDIF core-113.00.00/src/bigstring.mli000066400000000000000000000421651256461075500162510ustar00rootroot00000000000000(** String type based on [Bigarray], for use in I/O and C-bindings *) open Core_kernel.Std open Unix include module type of Core_kernel.Std.Bigstring with type t = Core_kernel.Std.Bigstring.t (** Type of I/O errors *) exception IOError of int * (** Number of bytes successfully read/written before error *) exn (** The occurred exception (e.g. Unix_error, End_of_file) *) (** {6 Input functions} *) val read : ?min_len : int -> file_descr -> ?pos : int -> ?len : int -> t -> int (** [read ?min_len fd ?pos ?len bstr] reads at least [min_len] (must be greater than or equal zero) and at most [len] (must be greater than or equal to [min_len]) bytes from file descriptor [fd], and writes them to bigstring [bstr] starting at position [pos]. @return the number of bytes actually read. [read] returns zero only if [len = 0]. If [len > 0] and there's nothing left to read, [read] raises to indicate EOF even if [min_len = 0]. NOTE: even if [len] is zero, there may still be errors when reading from the descriptor! @raise Invalid_argument if the designated ranges are out of bounds. @raise IOError in the case of input errors, or on EOF if the minimum length could not be read. @param pos default = 0 @param min_len default = 0 @param len default = [length bstr - pos] *) val really_read : file_descr -> ?pos : int -> ?len : int -> t -> unit (** [really_read fd ?pos ?len bstr] reads [len] bytes from file descriptor [fd], and writes them to bigstring [bstr] starting at position [pos]. @raise Invalid_argument if the designated range is out of bounds. @raise IOError in the case of input errors, or on EOF. @param pos default = 0 @param len default = [length bstr - pos] *) val really_recv : file_descr -> ?pos : int -> ?len : int -> t -> unit (** [really_recv sock ?pos ?len bstr] receives [len] bytes from socket [sock], and writes them to bigstring [bstr] starting at position [pos]. If [len] is zero, the function returns immediately without performing the underlying system call. @raise Invalid_argument if the designated range is out of bounds. @raise IOError in the case of input errors, or on EOF. @param pos default = 0 @param len default = [length bstr - pos] *) val recvfrom_assume_fd_is_nonblocking : file_descr -> ?pos : int -> ?len : int -> t -> int * sockaddr (** [recvfrom_assume_fd_is_nonblocking sock ?pos ?len bstr] reads up to [len] bytes into bigstring [bstr] starting at position [pos] from socket [sock] without yielding to other OCaml-threads. @return the number of bytes actually read and the socket address of the client. @raise Unix_error in the case of input errors. @raise Invalid_argument if the designated range is out of bounds. @param pos default = 0 @param len default = [length bstr - pos] *) val read_assume_fd_is_nonblocking : file_descr -> ?pos : int -> ?len : int -> t -> Syscall_result.Int.t (** [read_assume_fd_is_nonblocking fd ?pos ?len bstr] reads up to [len] bytes into bigstring [bstr] starting at position [pos] from file descriptor [fd] without yielding to other OCaml-threads. @return the number of bytes actually read. @raise Invalid_argument if the designated range is out of bounds. @param pos default = 0 @param len default = [length bstr - pos] *) val pread_assume_fd_is_nonblocking : file_descr -> offset : int -> ?pos : int -> ?len : int -> t -> int (** [pread_assume_fd_is_nonblocking fd ~offset ?pos ?len bstr] reads up to [len] bytes from file descriptor [fd] at offset [offset], and writes them to bigstring [bstr] starting at position [pos]. The fd must be capable of seeking, and the current file offset used for a regular [read()] is unchanged. Please see 'man pread' for more information. @return the number of bytes actually read. @raise Invalid_argument if the designated range is out of bounds. @raise Unix_error in the case of input errors. @param pos default = 0 @param len default = [length bstr - pos] *) val input : ?min_len : int -> in_channel -> ?pos : int -> ?len : int -> t -> int (** [input ?min_len ic ?pos ?len bstr] tries to read [len] bytes (guarantees to read at least [min_len] bytes (must be greater than or equal to zero and smaller or equal to [len]), if possible, before returning) from input channel [ic], and writes them to bigstring [bstr] starting at position [pos]. @return the number of bytes actually read. NOTE: even if [len] is zero, there may still be errors when reading from the descriptor, which will be done if the internal buffer is empty! NOTE: if at least [len] characters are available in the input channel buffer and if [len] is not zero, data will only be fetched from the channel buffer. Otherwise data will be read until at least [min_len] characters are available. @raise Invalid_argument if the designated range is out of bounds. @raise IOError in the case of input errors, or on premature EOF. @param pos default = 0 @param min_len default = 0 @param len default = [length bstr - pos] *) val really_input : in_channel -> ?pos : int -> ?len : int -> t -> unit (** [really_input ic ?pos ?len bstr] reads exactly [len] bytes from input channel [ic], and writes them to bigstring [bstr] starting at position [pos]. @raise Invalid_argument if the designated range is out of bounds. @raise IOError in the case of input errors, or on premature EOF. @param pos default = 0 @param len default = [length bstr - pos] *) (** {6 Output functions} *) val really_write : file_descr -> ?pos : int -> ?len : int -> t -> unit (** [really_write fd ?pos ?len bstr] writes [len] bytes in bigstring [bstr] starting at position [pos] to file descriptor [fd]. @raise Invalid_argument if the designated range is out of bounds. @raise IOError in the case of output errors. @param pos default = 0 @param len default = [length bstr - pos] *) (** [really_send_no_sigpipe sock ?pos ?len bstr] sends [len] bytes in bigstring [bstr] starting at position [pos] to socket [sock] without blocking and ignoring [SIGPIPE]. @raise Invalid_argument if the designated range is out of bounds. @raise IOError in the case of output errors. @param pos default = 0 @param len default = [length bstr - pos] [really_send_no_sigpipe] is not implemented on some platforms, in which case it is an [Error] value that indicates that it is unimplemented. *) val really_send_no_sigpipe : (file_descr -> ?pos : int -> ?len : int -> t -> unit) Or_error.t val send_nonblocking_no_sigpipe : (file_descr -> ?pos : int -> ?len : int -> t -> Syscall_result.Int.t) Or_error.t (** [send_nonblocking_no_sigpipe sock ?pos ?len bstr] tries to send [len] bytes in bigstring [bstr] starting at position [pos] to socket [sock]. @return [bytes_written]. @raise Invalid_argument if the designated range is out of bounds. @param pos default = 0 @param len default = [length bstr - pos] *) val sendto_nonblocking_no_sigpipe : (file_descr -> ?pos : int -> ?len : int -> t -> sockaddr -> Syscall_result.Int.t ) Or_error.t (** [sendto_nonblocking_no_sigpipe sock ?pos ?len bstr sockaddr] tries to send [len] bytes in bigstring [bstr] starting at position [pos] to socket [sock] using address [addr]. @return [bytes_written]. @raise Invalid_argument if the designated range is out of bounds. @param pos default = 0 @param len default = [length bstr - pos] *) val write : file_descr -> ?pos : int -> ?len : int -> t -> int (** [write fd ?pos ?len bstr] writes [len] bytes in bigstring [bstr] starting at position [pos] to file descriptor [fd]. @return the number of bytes actually written. @raise Unix_error in the case of output errors. @raise Invalid_argument if the designated range is out of bounds. @param pos default = 0 @param len default = [length bstr - pos] *) val pwrite_assume_fd_is_nonblocking : file_descr -> offset : int -> ?pos : int -> ?len : int -> t -> int (** [pwrite_assume_fd_is_nonblocking fd ~offset ?pos ?len bstr] writes up to [len] bytes of bigstring [bstr] starting at position [pos] to file descriptor [fd] at position [offset]. The fd must be capable of seeking, and the current file offset used for non-positional [read()]/[write()] calls is unchanged. @return the number of bytes written. @raise Invalid_argument if the designated range is out of bounds. @raise Unix_error in the case of input errors. @param pos default = 0 @param len default = [length bstr - pos] *) val write_assume_fd_is_nonblocking : file_descr -> ?pos : int -> ?len : int -> t -> int (** [write_assume_fd_is_nonblocking fd ?pos ?len bstr] writes [len] bytes in bigstring [bstr] starting at position [pos] to file descriptor [fd] without yielding to other OCaml-threads. @return the number of bytes actually written. @raise Unix_error in the case of output errors. @raise Invalid_argument if the designated range is out of bounds. @param pos default = 0 @param len default = [length bstr - pos] *) val writev : file_descr -> ?count : int -> t Core_unix.IOVec.t array -> int (** [writev fd ?count iovecs] writes [count] [iovecs] of bigstrings to file descriptor [fd]. @return the number of bytes written. @raise Unix_error in the case of output errors. @raise Invalid_argument if count is out of range. @param count default = [Array.length iovecs] *) val writev_assume_fd_is_nonblocking : file_descr -> ?count : int -> t Core_unix.IOVec.t array -> int (** [writev_assume_fd_is_nonblocking fd ?count iovecs] writes [count] [iovecs] of bigstrings to file descriptor [fd] without yielding to other OCaml-threads. @return the number of bytes actually written. @raise Unix_error in the case of output errors. @raise Invalid_argument if the designated range is out of bounds. @param count default = [Array.length iovecs] *) val recvmmsg_assume_fd_is_nonblocking : (file_descr -> ?count : int -> ?srcs : sockaddr array -> t Core_unix.IOVec.t array -> lens : int array -> int) Or_error.t (** [recvmmsg_assume_fd_is_nonblocking fd iovecs ~count ~lens] receives up to [count] messages into [iovecs] from file descriptor [fd] without yielding to other OCaml threads. If [~count] is supplied, it must be that [0 <= count <= Array.length iovecs]. If [~srcs] is supplied, save the source addresses for corresponding recieved messages there. If supplied, [Array.length srcs] must be [>= count]. Save the lengths of the received messages in [lens]. It is required that [Array.length lens >= count]. If an IOVec isn't long enough for its corresponding message, excess bytes may be discarded, depending on the type of socket the message is received from. While the [recvmmsg] system call itself does return details of such truncation, etc., those details are not (yet) passed through this interface. @see "recvmmsg(2)" re. the underlying system call. @return the number of messages actually read, or a negative number to indicate EWOULDBLOCK or EAGAIN. This is a compromise to mitigate the exception overhead for what ends up being a very common result with our use of [recvmmsg]. @raise Unix_error in the case of output errors. @raise Invalid_argument if the designated range is out of bounds. @param count default = [Array.length iovecs] *) val sendmsg_nonblocking_no_sigpipe : (file_descr -> ?count : int -> t Core_unix.IOVec.t array -> int option) Or_error.t (** [sendmsg_nonblocking_no_sigpipe sock ?count iovecs] sends [count] [iovecs] of bigstrings to socket [sock]. @return [Some bytes_written], or [None] if the operation would have blocked. This system call will not cause signal [SIGPIPE] if an attempt is made to write to a socket that was closed by the other side. @raise Unix_error in the case of output errors. @raise Invalid_argument if [count] is out of range. @param count default = [Array.length iovecs] *) val output : ?min_len : int -> out_channel -> ?pos : int -> ?len : int -> t -> int (** [output ?min_len oc ?pos ?len bstr] tries to output [len] bytes (guarantees to write at least [min_len] bytes (must be equal to or greater than zero), if possible, before returning) from bigstring [bstr] starting at position [pos] to output channel [oc]. @return the number of bytes actually written. NOTE: you may need to flush [oc] to make sure that the data is actually sent. NOTE: if [len] characters fit into the channel buffer completely, they will be buffered. Otherwise writes will be attempted until at least [min_len] characters have been sent. @raise Invalid_argument if the designated range is out of bounds. @raise IOError in the case of output errors. The [IOError]-argument counting the number of successful bytes includes those that have been transferred to the channel buffer before the error. @param pos default = 0 @param min_len default = 0 @param len default = [length bstr - pos] *) val really_output : out_channel -> ?pos : int -> ?len : int -> t -> unit (** [really_output oc ?pos ?len bstr] outputs exactly [len] bytes from bigstring [bstr] starting at position [pos] to output channel [oc]. @raise Invalid_argument if the designated range is out of bounds. @raise IOError in the case of output errors. The [IOError]-argument counting the number of successful bytes includes those that have been transferred to the channel buffer before the error. @param pos default = 0 @param len default = [length bstr - pos] *) (** {6 Unsafe functions} *) external unsafe_read_assume_fd_is_nonblocking : file_descr -> pos : int -> len : int -> t -> Syscall_result.Int.t = "bigstring_read_assume_fd_is_nonblocking_stub" (** [unsafe_read_assume_fd_is_nonblocking fd ~pos ~len bstr] similar to {!Bigstring.read_assume_fd_is_nonblocking}, but does not perform any bounds checks. Will crash on bounds errors! *) external unsafe_write : file_descr -> pos : int -> len : int -> t -> int = "bigstring_write_stub" (** [unsafe_write fd ~pos ~len bstr] similar to {!Bigstring.write}, but does not perform any bounds checks. Will crash on bounds errors! *) external unsafe_write_assume_fd_is_nonblocking : file_descr -> pos : int -> len : int -> t -> int = "bigstring_write_assume_fd_is_nonblocking_stub" (** [unsafe_write_assume_fd_is_nonblocking fd ~pos ~len bstr] similar to {!Bigstring.write_assume_fd_is_nonblocking}, but does not perform any bounds checks. Will crash on bounds errors! *) external unsafe_read : min_len : int -> file_descr -> pos : int -> len : int -> t -> int = "bigstring_read_stub" (** [unsafe_read ~min_len fd ~pos ~len bstr] similar to {!Bigstring.read}, but does not perform any bounds checks. Will crash on bounds errors! *) external unsafe_really_recv : file_descr -> pos : int -> len : int -> t -> unit = "bigstring_really_recv_stub" (** [unsafe_really_recv sock ~pos ~len bstr] similar to {!Bigstring.really_recv}, but does not perform any bounds checks. Will crash on bounds errors! *) external unsafe_really_write : file_descr -> pos : int -> len : int -> t -> unit = "bigstring_really_write_stub" (** [unsafe_really_write fd ~pos ~len bstr] similar to {!Bigstring.write}, but does not perform any bounds checks. Will crash on bounds errors! *) (** [unsafe_really_send_no_sigpipe sock ~pos ~len bstr] similar to {!Bigstring.send}, but does not perform any bounds checks. Will crash on bounds errors! *) val unsafe_really_send_no_sigpipe : (file_descr -> pos : int -> len : int -> t -> unit) Or_error.t (** [unsafe_send_nonblocking_no_sigpipe sock ~pos ~len bstr] similar to {!Bigstring.send_nonblocking_no_sigpipe}, but does not perform any bounds checks. Will crash on bounds errors! *) val unsafe_send_nonblocking_no_sigpipe : (file_descr -> pos : int -> len : int -> t -> Syscall_result.Int.t) Or_error.t external unsafe_writev : file_descr -> t Core_unix.IOVec.t array -> int -> int = "bigstring_writev_stub" (** [unsafe_writev fd iovecs count] similar to {!Bigstring.writev}, but does not perform any bounds checks. Will crash on bounds errors! *) (** [unsafe_sendmsg_nonblocking_no_sigpipe fd iovecs count] similar to {!Bigstring.sendmsg_nonblocking_no_sigpipe}, but does not perform any bounds checks. Will crash on bounds errors! *) val unsafe_sendmsg_nonblocking_no_sigpipe : (file_descr -> t Core_unix.IOVec.t array -> int -> int option) Or_error.t external unsafe_input : min_len : int -> in_channel -> pos : int -> len : int -> t -> int = "bigstring_input_stub" (** [unsafe_input ~min_len ic ~pos ~len bstr] similar to {!Bigstring.input}, but does not perform any bounds checks. Will crash on bounds errors! *) external unsafe_output : min_len : int -> out_channel -> pos : int -> len : int -> t -> int = "bigstring_output_stub" (** [unsafe_output ~min_len oc ~pos ~len bstr] similar to {!Bigstring.output}, but does not perform any bounds checks. Will crash on bounds errors! *) core-113.00.00/src/bigstring_marshal.ml000066400000000000000000000040671256461075500176060ustar00rootroot00000000000000module Extended_bigstring = Bigstring open Core_kernel.Std open Extended_bigstring include Core_kernel.Std.Bigstring_marshal external unsafe_unmarshal : pos : int -> len : int -> t -> 'a = "bigstring_unmarshal_stub" let unmarshal_from_sock ?buf sock = match buf with | None -> let buf_len = 4096 in let buf = create buf_len in really_recv sock ~len:Marshal.header_size buf; let data_len = marshal_data_size buf in let all_len = Marshal.header_size + data_len in let buf = if all_len <= buf_len then buf else create all_len in really_recv sock ~pos:Marshal.header_size ~len:data_len buf; unsafe_unmarshal ~pos:0 ~len:all_len buf | Some buf -> let buf_len = length buf in if buf_len < Marshal.header_size then failwith "Bigstring.unmarshal_from_sock: buffer cannot hold header"; really_recv sock ~len:Marshal.header_size buf; let data_len = marshal_data_size buf in let all_len = Marshal.header_size + data_len in if all_len > buf_len then failwith "Bigstring.unmarshal_from_sock: buffer cannot hold header + data"; really_recv sock ~pos:Marshal.header_size ~len:data_len buf; unsafe_unmarshal ~pos:0 ~len:all_len buf ;; let marshal_to_gen ?buf ?flags dest v ~f = let buf, len = match buf with | None -> let buf = marshal ?flags v in buf, length buf | Some buf -> buf, marshal_blit ?flags v buf in f dest buf ~len ;; let marshal_to_fd ?buf ?flags fd v = marshal_to_gen ?buf ?flags fd v ~f:(fun fd buf ~len -> really_write fd buf ~len) INCLUDE "core_config.mlh" IFDEF MSG_NOSIGNAL THEN let really_send_no_sigpipe = Or_error.ok_exn really_send_no_sigpipe let marshal_to_sock_no_sigpipe ?buf ?flags fd v = marshal_to_gen ?buf ?flags fd v ~f:(fun fd buf ~len -> really_send_no_sigpipe fd ?pos:None ?len:(Some len) buf) let marshal_to_sock_no_sigpipe = Ok marshal_to_sock_no_sigpipe ELSE let marshal_to_sock_no_sigpipe = Or_error.unimplemented "Bigstring_marshal.marshal_to_sock_no_sigpipe" ENDIF core-113.00.00/src/bigstring_marshal.mli000066400000000000000000000025121256461075500177500ustar00rootroot00000000000000(** Utility functions for marshalling to and from bigstring @author Markus Mottl *) open Core_kernel.Std open Bigstring include module type of Core_kernel.Std.Bigstring_marshal (** [marshal_to_fd ?buf fd v] marshals data [v] to file descriptor [fd] using marshalling buffer [buf], and marshalling flags [flags]. Raises input errors as in {!Bigstring.really_write}. @raise Failure if [buf] cannot hold enough data for marshalling. @param flags default = [] @param buf default = determined dynamically *) val marshal_to_fd : ?buf : t -> ?flags : Marshal.extern_flags list -> Unix.file_descr -> 'a -> unit (** [marshal_to_sock_no_sigpipe ?buf sock v] same as {!marshal_to_fd}, but writes to sockets only and uses {!Bigstring.really_send_no_sigpipe} to avoid [SIGPIPE] on sockets. *) val marshal_to_sock_no_sigpipe : (?buf : t -> ?flags : Marshal.extern_flags list -> Unix.file_descr -> 'a -> unit) Or_error.t (** [unmarshal_from_sock ?buf sock] unmarshals data from socket [sock] using unmarshalling buffer [buf]. Raises input errors as in {!Bigstring.really_recv}. @raise Failure if [buf] cannot hold enough data for unmarshalling. @param buf default = determined dynamically *) val unmarshal_from_sock : ?buf : t -> Unix.file_descr -> 'a core-113.00.00/src/bigstring_stubs.c000066400000000000000000000561141256461075500171310ustar00rootroot00000000000000#include "core_config.h" #define _FILE_OFFSET_BITS 64 #ifdef JSC_RECVMMSG #define _GNU_SOURCE /* recvmmsg */ #endif /* Defining _XOPEN_SOURCE on FreeBSD results in some other definitions (MSG_NOSIGNAL) being hidden. */ #ifdef __linux__ /* For pread/pwrite >= 500 */ /* For ipv6 >= 600 */ #define _XOPEN_SOURCE 600 #endif #include #include #include #include #include #include #ifdef __APPLE__ #include #define bswap_16 OSSwapInt16 #define bswap_32 OSSwapInt32 #define bswap_64 OSSwapInt64 #elif __GLIBC__ #include #include #else #include #include #define __BYTE_ORDER _BYTE_ORDER #define __LITTLE_ENDIAN _LITTLE_ENDIAN #define __BIG_ENDIAN _BIG_ENDIAN #define bswap_16 bswap16 #define bswap_32 bswap32 #define bswap_64 bswap64 #endif #include #include #include #include #include "recvmmsg.h" /* Initialisation */ static value *bigstring_exc_IOError = NULL; static value *bigstring_exc_End_of_file = NULL; static value *unix_error_exn = NULL; CAMLprim value bigstring_init_stub(value __unused v_unit) { bigstring_exc_IOError = caml_named_value("Bigstring.IOError"); bigstring_exc_End_of_file = caml_named_value("Bigstring.End_of_file"); unix_error_exn = caml_named_value("Unix.Unix_error"); #ifdef __GLIBC__ /* GLIBC uses a threshold internally as a cutoff between brk and mmap. Sadly, it nowadays employs a heuristic that may change this value dynamically. The call to mallopt suppresses this behavior, which made it hard to prevent C-heap fragmentation (e.g. in the writer). */ mallopt(M_MMAP_THRESHOLD, 131072); #endif if (unix_error_exn == NULL) caml_invalid_argument( "Exception Unix.Unix_error not initialized, please link unix.cma"); return Val_unit; } /* Exceptions */ static inline void raise_io_error(value v_n_good, value v_exc) { raise_with_two_args(*bigstring_exc_IOError, v_n_good, v_exc); } static inline value mk_unix_error_exn(int errcode, char *cmdname, value cmdarg) { CAMLparam0(); CAMLlocal3(name, err, arg); value res; arg = cmdarg == Nothing ? caml_copy_string("") : cmdarg; name = caml_copy_string(cmdname); err = unix_error_of_code(errcode); res = caml_alloc_small(4, 0); Field(res, 0) = *unix_error_exn; Field(res, 1) = err; Field(res, 2) = name; Field(res, 3) = arg; CAMLreturn(res); } static inline value mk_uerror_exn(char *cmdname, value cmdarg) { return mk_unix_error_exn(errno, cmdname, cmdarg); } static inline void raise_unix_io_error( value v_n_good, char *cmdname, value cmdarg) { value v_uerror = mk_uerror_exn(cmdname, cmdarg); raise_io_error(v_n_good, v_uerror); } static inline void raise_eof_io_error(value v_n_good) { #if defined(JSC_OCAML_4_02) value v_eof_exn = *bigstring_exc_End_of_file; #else value v_eof_exn = caml_alloc_small(1, 0); Field(v_eof_exn, 0) = *bigstring_exc_End_of_file; #endif raise_io_error(v_n_good, v_eof_exn); } /* Input of bigstrings from file descriptors */ CAMLprim value bigstring_read_stub( value v_min_len, value v_fd, value v_pos, value v_len, value v_bstr) { CAMLparam1(v_bstr); size_t min_len = Long_val(v_min_len); int fd = Int_val(v_fd); size_t init_len = Long_val(v_len); size_t len = init_len; ssize_t n_read; char *bstr_start = get_bstr(v_bstr, v_pos); char *bstr = bstr_start; char *bstr_min = bstr_start + min_len; caml_enter_blocking_section(); do { do { n_read = read(fd, bstr, len); } while (n_read == -1 && errno == EINTR); if (n_read <= 0) { value v_n_good = Val_long(bstr - bstr_start); caml_leave_blocking_section(); if (n_read == 0) { if (init_len == 0) CAMLreturn(Val_long(0)); else raise_eof_io_error(v_n_good); } else raise_unix_io_error(v_n_good, "read", Nothing); } else { bstr += n_read; len -= n_read; } } while (bstr < bstr_min); caml_leave_blocking_section(); CAMLreturn(Val_long(bstr - bstr_start)); } CAMLprim value bigstring_read_assume_fd_is_nonblocking_stub( value v_fd, value v_pos, value v_len, value v_bstr) { struct caml_ba_array *ba = Caml_ba_array_val(v_bstr); char *bstr = (char *) ba->data + Long_val(v_pos); size_t len = Long_val(v_len); ssize_t n_read; if ((len > THREAD_IO_CUTOFF) || (ba->flags & CAML_BA_MAPPED_FILE)) { Begin_roots1(v_bstr); caml_enter_blocking_section(); n_read = read(Int_val(v_fd), bstr, len); caml_leave_blocking_section(); End_roots(); } else n_read = read(Int_val(v_fd), bstr, len); if (n_read == -1) n_read = -errno; return Val_long(n_read); } CAMLprim value bigstring_pread_assume_fd_is_nonblocking_stub( value v_fd, value v_offset, value v_pos, value v_len, value v_bstr) { char *bstr = get_bstr(v_bstr, v_pos); size_t len = Long_val(v_len); ssize_t n_read; n_read = pread(Int_val(v_fd), bstr, len, Long_val(v_offset)); if (n_read == -1) uerror("bigstring_pread_assume_fd_is_nonblocking_stub", Nothing); return Val_long(n_read); } /* Input of bigstrings from sockets */ CAMLprim value bigstring_really_recv_stub( value v_sock, value v_pos, value v_len, value v_bstr) { size_t len = Long_val(v_len); if (len == 0) return Val_unit; else { CAMLparam1(v_bstr); char *bstr = get_bstr(v_bstr, v_pos); int sock = Int_val(v_sock); ssize_t n_read; size_t n_total = 0; caml_enter_blocking_section(); while (len > 0) { n_read = recv(sock, bstr, len, MSG_WAITALL); if (n_read <= 0) { if (n_read != -1 || errno != EINTR) { value v_n_total = Val_long(n_total); caml_leave_blocking_section(); if (n_read == 0) raise_eof_io_error(v_n_total); else raise_unix_io_error(v_n_total, "really_recv", Nothing); } } else { len -= n_read; bstr += n_read; n_total += n_read; } } caml_leave_blocking_section(); CAMLreturn(Val_unit); } } CAMLprim value bigstring_recvfrom_assume_fd_is_nonblocking_stub( value v_sock, value v_pos, value v_len, value v_bstr) { CAMLparam1(v_bstr); CAMLlocal1(v_addr); struct caml_ba_array *ba = Caml_ba_array_val(v_bstr); char *bstr = (char *) ba->data + Long_val(v_pos); size_t len = Long_val(v_len); ssize_t n_read; union sock_addr_union addr; socklen_param_type addr_len = sizeof(addr); value v_res; if (len > THREAD_IO_CUTOFF) { caml_enter_blocking_section(); n_read = recvfrom(Int_val(v_sock), bstr, len, 0, &addr.s_gen, &addr_len); caml_leave_blocking_section(); } else n_read = recvfrom(Int_val(v_sock), bstr, len, 0, &addr.s_gen, &addr_len); if (n_read == -1) uerror("bigstring_recvfrom_assume_fd_is_nonblocking", Nothing); v_addr = alloc_sockaddr(&addr, addr_len, -1); v_res = caml_alloc_small(2, 0); Field(v_res, 0) = Val_long(n_read); Field(v_res, 1) = v_addr; CAMLreturn(v_res); } /* I/O of bigstrings from channels */ typedef off_t file_offset; #define IO_BUFFER_SIZE 65536 struct channel { int fd; /* Unix file descriptor */ file_offset offset; /* Absolute position of fd in the file */ char * end; /* Physical end of the buffer */ char * curr; /* Current position in the buffer */ char * max; /* Logical end of the buffer (for input) */ void * mutex; /* Placeholder for mutex (for systhreads) */ struct channel * next, * prev;/* Double chaining of channels (flush_all) */ int revealed; /* For Cash only */ int old_revealed; /* For Cash only */ int refcount; /* For flush_all and for Cash */ int flags; /* Bitfield */ char buff[IO_BUFFER_SIZE]; /* The buffer itself */ }; CAMLextern void (*caml_channel_mutex_lock) (struct channel *); CAMLextern void (*caml_channel_mutex_unlock) (struct channel *); #define Channel(v) (*((struct channel **) (Data_custom_val(v)))) #define Lock(channel) \ if (caml_channel_mutex_lock != NULL) (*caml_channel_mutex_lock)(channel) #define Unlock(channel) \ if (caml_channel_mutex_unlock != NULL) (*caml_channel_mutex_unlock)(channel) CAMLprim value bigstring_input_stub( value v_min_len, value v_chan, value v_pos, value v_len, value v_bstr) { CAMLparam2(v_chan, v_bstr); struct channel *chan = Channel(v_chan); char *bstr_start = get_bstr(v_bstr, v_pos); char *bstr = bstr_start; size_t init_bstr_len = Long_val(v_len); size_t bstr_len = init_bstr_len; size_t min_len = Long_val(v_min_len); size_t avail = chan->max - chan->curr; Lock(chan); if (avail) { int got_all = bstr_len <= avail; size_t to_write = got_all ? bstr_len : avail; memcpy(bstr, chan->curr, to_write); if (got_all) { chan->curr += to_write; Unlock(chan); CAMLreturn(v_len); } else { bstr += to_write; bstr_len -= to_write; min_len -= to_write; } } /* Buffer empty now */ { int fd = chan->fd; char *bstr_min = bstr + min_len; char *bstr_max = bstr + bstr_len; struct iovec iovecs[2]; struct iovec *bstr_iov = &iovecs[0]; struct iovec *buff_iov = &iovecs[1]; ssize_t n_read; bstr_iov->iov_base = bstr; bstr_iov->iov_len = bstr_len; buff_iov->iov_base = chan->buff; buff_iov->iov_len = chan->end - chan->buff; caml_enter_blocking_section(); while (1) { n_read = readv(fd, iovecs, 2); if (n_read <= 0) { if (n_read == -1) { /* Interrupt and error handling */ if (errno == EINTR) continue; else { value v_n_good = Val_long((char *) bstr_iov->iov_base - bstr_start); /* Set buffer to empty as required */ chan->curr = chan->max; caml_leave_blocking_section(); Unlock(chan); raise_unix_io_error(v_n_good, "input", Nothing); } } else { /* Zero-read: set buffer to empty as required */ assert(n_read == 0); chan->curr = chan->max; if (init_bstr_len == 0) { caml_leave_blocking_section(); Unlock(chan); CAMLreturn(Val_long(0)); } else { /* EOF handling */ value v_n_good = Val_long((char *) bstr_iov->iov_base - bstr_start); caml_leave_blocking_section(); Unlock(chan); raise_eof_io_error(v_n_good); } } } else { /* Successful read */ chan->offset += n_read; bstr = (char *) bstr_iov->iov_base + n_read; if (bstr >= bstr_min) { /* Sufficient data read */ if (bstr > bstr_max) { /* Buffer contains extra data */ chan->max = &chan->buff[bstr - bstr_max]; chan->curr = chan->buff; caml_leave_blocking_section(); Unlock(chan); CAMLreturn(v_len); } else { /* Buffer empty; set it so */ chan->curr = chan->max; caml_leave_blocking_section(); Unlock(chan); CAMLreturn(Val_long(bstr - bstr_start)); } } else { /* Insufficient data */ bstr_iov->iov_base = bstr; bstr_iov->iov_len -= n_read; } } } } } CAMLprim value bigstring_output_stub( value v_min_len, value v_chan, value v_pos, value v_len, value v_bstr) { CAMLparam2(v_chan, v_bstr); struct channel *chan = Channel(v_chan); char *bstr = get_bstr(v_bstr, v_pos); size_t bstr_len = Long_val(v_len); Lock(chan); if (bstr_len <= (size_t) (chan->end - chan->curr)) { /* Buffer can store all data */ memcpy(chan->curr, bstr, bstr_len); chan->curr += bstr_len; Unlock(chan); CAMLreturn(v_len); } else { /* Buffer cannot store all data */ int fd = chan->fd; size_t buff_len = chan->curr - chan->buff; char *bstr_min = bstr + Long_val(v_min_len); struct iovec iovecs[2]; struct iovec *buff_iov = &iovecs[0]; struct iovec *bstr_iov = &iovecs[1]; ssize_t written; buff_iov->iov_base = chan->buff; buff_iov->iov_len = buff_len; bstr_iov->iov_base = bstr; bstr_iov->iov_len = bstr_len; caml_enter_blocking_section(); while (1) { written = writev(fd, iovecs, 2); if (written == -1) { /* Interrupt and error handling */ if (errno == EINTR) continue; if ((errno == EAGAIN || errno == EWOULDBLOCK) && buff_iov->iov_len + bstr_iov->iov_len > 1) { /* Call might have blocked, try writing a single byte */ if (buff_len) { buff_iov->iov_len = 1; bstr_iov->iov_len = 0; } else bstr_iov->iov_len = 1; continue; } else { /* Write (maybe of even one byte only) failed */ value v_n_good = Val_long((char *) bstr_iov->iov_base - bstr); chan->curr = chan->buff + buff_len; if (buff_len) memmove(chan->buff, buff_iov->iov_base, buff_len); caml_leave_blocking_section(); Unlock(chan); raise_unix_io_error(v_n_good, "output", Nothing); } } else { /* Write successful */ chan->offset += written; if (buff_len > (size_t) written) { /* Buffer was partially written only; continue */ buff_iov->iov_base = (char *) buff_iov->iov_base + written; buff_len -= written; buff_iov->iov_len = buff_len; } else { /* Buffer is empty now */ size_t bstr_written = written - buff_len; char *new_bstr = (char *) bstr_iov->iov_base + bstr_written; if (new_bstr >= bstr_min) { /* Sufficient data was sent */ chan->curr = chan->buff; caml_leave_blocking_section(); Unlock(chan); CAMLreturn(Val_long(new_bstr - bstr)); } else { /* Not yet done */ bstr_iov->iov_base = new_bstr; buff_len = 0; buff_iov->iov_len = buff_len; bstr_len -= bstr_written; bstr_iov->iov_len = bstr_len; } } } } } } /* Output macros and functions */ #define MakeReallyOutputFun(NAME, CALL_WRITE) \ CAMLprim value bigstring_really_##NAME##_stub( \ value v_fd, value v_pos, value v_len, value v_bstr) \ { \ CAMLparam1(v_bstr); \ int fd = Int_val(v_fd); \ size_t len = Long_val(v_len); \ ssize_t written; \ char *bstr_start = get_bstr(v_bstr, v_pos); \ char *bstr = bstr_start; \ char *bstr_max = bstr + len; \ caml_enter_blocking_section(); \ do { \ CALL_WRITE; \ if (written == -1) { \ if (errno == EINTR) continue; \ { \ value v_n_good = Val_long(bstr - bstr_start); \ caml_leave_blocking_section(); \ raise_unix_io_error(v_n_good, STR(really_##NAME), Nothing); \ } \ }; \ len -= written; \ bstr += written; \ } while (bstr < bstr_max); \ caml_leave_blocking_section(); \ CAMLreturn(Val_unit); \ } MakeReallyOutputFun(write, written = write(fd, bstr, len)) CAMLprim value bigstring_write_stub( value v_fd, value v_pos, value v_len, value v_bstr) { CAMLparam1(v_bstr); char *bstr = get_bstr(v_bstr, v_pos); size_t len = Long_val(v_len); ssize_t written; caml_enter_blocking_section(); written = write(Int_val(v_fd), bstr, len); caml_leave_blocking_section(); if (written == -1) uerror("write", Nothing); CAMLreturn(Val_long(written)); } CAMLprim value bigstring_pwrite_assume_fd_is_nonblocking_stub( value v_fd, value v_offset, value v_pos, value v_len, value v_bstr) { char *bstr = get_bstr(v_bstr, v_pos); size_t len = Long_val(v_len); ssize_t written; written = pwrite(Int_val(v_fd), bstr, len, Long_val(v_offset)); if (written == -1) uerror("bigstring_pwrite_assume_fd_is_nonblocking_stub", Nothing); return Val_long(written); } CAMLprim value bigstring_write_assume_fd_is_nonblocking_stub( value v_fd, value v_pos, value v_len, value v_bstr) { struct caml_ba_array *ba = Caml_ba_array_val(v_bstr); char *bstr = (char *) ba->data + Long_val(v_pos); size_t len = Long_val(v_len); ssize_t written; if ((len > THREAD_IO_CUTOFF) || (ba->flags & CAML_BA_MAPPED_FILE)) { Begin_roots1(v_bstr); caml_enter_blocking_section(); written = write(Int_val(v_fd), bstr, len); caml_leave_blocking_section(); End_roots(); } else written = write(Int_val(v_fd), bstr, len); if (written == -1) uerror("write_assume_fd_is_nonblocking", Nothing); return Val_long(written); } static inline ssize_t writev_in_blocking_section( value v_fd, value v_iovecs, struct iovec *iovecs, int count) { ssize_t ret; CAMLparam1(v_iovecs); /* To protect bigstrings outside of OCaml lock */ caml_enter_blocking_section(); ret = writev(Int_val(v_fd), iovecs, count); free(iovecs); caml_leave_blocking_section(); CAMLreturn(ret); } CAMLprim value bigstring_writev_stub(value v_fd, value v_iovecs, value v_count) { int count = Int_val(v_count); size_t total_len = 0; struct iovec *iovecs = copy_iovecs(&total_len, v_iovecs, count); ssize_t ret = writev_in_blocking_section(v_fd, v_iovecs, iovecs, count); if (ret == -1) uerror("writev", Nothing); return Val_long(ret); } __pure static inline int contains_mmapped(value v_iovecs, int n) { for (--n; n >= 0; --n) { value v_iovec = Field(v_iovecs, n); int flags = Caml_ba_array_val(Field(v_iovec, 0))->flags; if (unlikely(flags & CAML_BA_MAPPED_FILE)) return 1; } return 0; } CAMLprim value bigstring_writev_assume_fd_is_nonblocking_stub( value v_fd, value v_iovecs, value v_count) { int count = Int_val(v_count); size_t total_len = 0; struct iovec *iovecs = copy_iovecs(&total_len, v_iovecs, count); ssize_t ret; if (total_len > THREAD_IO_CUTOFF || contains_mmapped(v_iovecs, count)) /* NOTE: writev_in_blocking_section frees iovecs */ ret = writev_in_blocking_section(v_fd, v_iovecs, iovecs, count); else { ret = writev(Int_val(v_fd), iovecs, count); free(iovecs); } if (ret == -1) uerror("writev_assume_fd_is_nonblocking", Nothing); return Val_long(ret); } #ifdef JSC_RECVMMSG CAMLprim value bigstring_recvmmsg_assume_fd_is_nonblocking_stub( value v_fd, value v_iovecs, value v_count, value v_srcs, value v_lens) { CAMLparam5(v_fd, v_iovecs, v_count, v_srcs, v_lens); CAMLlocal4(v_iovec, v_buf, v_pos, v_len); unsigned i; int n_read; unsigned count; count = (unsigned) Long_val(v_count); /* On 32-bit platforms, sizeof(unsigned) == sizeof(intnat); it thus suffices to check that [v_count] is not negative. On 64-bit platforms with unsigned being 32 bit and intnat being 64 bit, we need the second check to ensure there is no truncation. Note that "(intnat) count" zero-extends to 64-bit width. This check actually subsumes the [v_count] being negative check. If this code were built on a platform where both unsigned and intnat were 64 bit, then it should still work, by analogy with the all-32 bit case. */ if (Long_val(v_count) < 0 || (intnat) count != Long_val(v_count)) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "v_count exceeds unsigned int"); } if (!Is_block(v_lens)) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "v_lens is not an array"); } if (Wosize_val(v_lens) < count) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "length v_lens < count"); } if (count > RECVMMSG_MAX_COUNT) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "v_count exceeds RECVMMSG_MAX_COUNT"); } { /* For a big count (~100), a mostly idle system spent a substantial amount of time (~10%) copying the iovec fields back and forth. This was greatly improved by passing a small (~4) number of buffers. */ struct mmsghdr hdrs[RECVMMSG_MAX_COUNT]; struct iovec iovecs[RECVMMSG_MAX_COUNT]; for (i = 0; i < count; i++) { v_iovec = Field(v_iovecs, i); v_buf = Field(v_iovec, 0); v_pos = Field(v_iovec, 1); v_len = Field(v_iovec, 2); iovecs[i].iov_base = get_bstr(v_buf, v_pos); iovecs[i].iov_len = Long_val(v_len); } n_read = recvmmsg_assume_fd_is_nonblocking(v_fd, iovecs, count, v_srcs, hdrs); for (i = 0; (int) i < n_read; i++) { Field(v_lens, i) = Val_long(hdrs[i].msg_len); } } CAMLreturn(Val_int(n_read)); } #endif /* JSC_RECVMMSG */ #ifdef MSG_NOSIGNAL MakeReallyOutputFun(send_no_sigpipe, written = send(fd, bstr, len, MSG_NOSIGNAL)) static int nonblocking_no_sigpipe_flag = MSG_DONTWAIT | MSG_NOSIGNAL; CAMLprim value bigstring_send_nonblocking_no_sigpipe_stub( value v_fd, value v_pos, value v_len, value v_bstr) { char *bstr = get_bstr(v_bstr, v_pos); ssize_t ret = send(Int_val(v_fd), bstr, Long_val(v_len), nonblocking_no_sigpipe_flag); if (ret == -1) ret = -errno; return Val_long(ret); } CAMLprim value bigstring_sendto_nonblocking_no_sigpipe_stub( value v_fd, value v_pos, value v_len, value v_bstr, value v_addr) { char *bstr = get_bstr(v_bstr, v_pos); union sock_addr_union addr; socklen_param_type addr_len = sizeof(addr); ssize_t ret; get_sockaddr(v_addr, &addr, &addr_len); ret = sendto( Int_val(v_fd), bstr, Long_val(v_len), nonblocking_no_sigpipe_flag, &addr.s_gen, addr_len); if (ret == -1) ret = -errno; return Val_long(ret); } CAMLprim value bigstring_sendmsg_nonblocking_no_sigpipe_stub( value v_fd, value v_iovecs, value v_count) { int count = Int_val(v_count); size_t total_len = 0; struct iovec *iovecs = copy_iovecs(&total_len, v_iovecs, count); struct msghdr msghdr = { NULL, 0, NULL, 0, NULL, 0, 0 }; ssize_t ret; if (total_len > THREAD_IO_CUTOFF || contains_mmapped(v_iovecs, count)) { Begin_roots1(v_iovecs); caml_enter_blocking_section(); msghdr.msg_iov = iovecs; msghdr.msg_iovlen = count; ret = sendmsg(Int_val(v_fd), &msghdr, nonblocking_no_sigpipe_flag); free(iovecs); caml_leave_blocking_section(); End_roots(); } else { msghdr.msg_iov = iovecs; msghdr.msg_iovlen = count; ret = sendmsg(Int_val(v_fd), &msghdr, nonblocking_no_sigpipe_flag); free(iovecs); } if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) uerror("sendmsg_nonblocking_no_sigpipe", Nothing); return Val_long(ret); } #else #warning "MSG_NOSIGNAL not defined; bigstring_send{,msg}_noblocking_no_sigpipe not implemented" #warning "Try compiling on Linux?" #endif core-113.00.00/src/bigsubstring.ml000066400000000000000000000000411256461075500165750ustar00rootroot00000000000000include Core_kernel.Bigsubstring core-113.00.00/src/binable.ml000066400000000000000000000000341256461075500154710ustar00rootroot00000000000000include Core_kernel.Binable core-113.00.00/src/binable0.ml000066400000000000000000000000351256461075500155520ustar00rootroot00000000000000include Core_kernel.Binable0 core-113.00.00/src/binary_packing.ml000066400000000000000000000000431256461075500170550ustar00rootroot00000000000000include Core_kernel.Binary_packing core-113.00.00/src/blang.ml000066400000000000000000000000321256461075500151560ustar00rootroot00000000000000include Core_kernel.Blang core-113.00.00/src/bool.ml000066400000000000000000000000311256461075500150250ustar00rootroot00000000000000include Core_kernel.Bool core-113.00.00/src/bounded_int_table.ml000066400000000000000000000000461256461075500175410ustar00rootroot00000000000000include Core_kernel.Bounded_int_table core-113.00.00/src/bucket.ml000066400000000000000000000000331256461075500153510ustar00rootroot00000000000000include Core_kernel.Bucket core-113.00.00/src/byte_units.ml000066400000000000000000000000371256461075500162650ustar00rootroot00000000000000include Core_kernel.Byte_units core-113.00.00/src/caml.ml000066400000000000000000000002311256461075500150100ustar00rootroot00000000000000include Core_kernel.Std.Caml module Condition = Condition module Mutex = Mutex module Thread = Thread module Unix = Unix module UnixLabels = UnixLabels core-113.00.00/src/check_std.ml000066400000000000000000000011151256461075500160250ustar00rootroot00000000000000(* These checks are here rather than in their corresponding modules because we want to check a property of the module as it is exported in Core.Std. *) open Std TEST_MODULE = struct module Check = Core_kernel.Std.Comparable.Check_sexp_conversion include Check (struct include Time let examples = [ epoch ] end) include Check (struct include Time.Ofday let examples = [ start_of_day ] end) include Check (struct include Time.Span let examples = [ of_sec 13. ] end) include Check (struct include Month let examples = all end) end core-113.00.00/src/command.ml000066400000000000000000002005671256461075500155300ustar00rootroot00000000000000open Core_kernel.Std module Unix = Core_unix module Filename = Core_filename let unwords xs = String.concat ~sep:" " xs let unparagraphs xs = String.concat ~sep:"\n\n" xs exception Failed_to_parse_command_line of string let die fmt = Printf.ksprintf (fun msg () -> raise (Failed_to_parse_command_line msg)) fmt let help_screen_compare a b = match (a, b) with | (_, "[-help]") -> -1 | ("[-help]", _) -> 1 | (_, "[-version]") -> -1 | ("[-version]", _) -> 1 | (_, "[-build-info]") -> -1 | ("[-build-info]", _) -> 1 | (_, "help") -> -1 | ("help", _) -> 1 | (_, "version") -> -1 | ("version", _) -> 1 | _ -> 0 module Format : sig module V1 : sig type t = { name : string; doc : string; aliases : string list; } with sexp val sort : t list -> t list val to_string : t list -> string end end = struct module V1 = struct type t = { name : string; doc : string; aliases : string list; } with sexp let sort ts = List.stable_sort ts ~cmp:(fun a b -> help_screen_compare a.name b.name) let word_wrap text width = let chunks = String.split text ~on:'\n' in List.concat_map chunks ~f:(fun text -> let words = String.split text ~on:' ' |> List.filter ~f:(fun word -> not (String.is_empty word)) in match List.fold words ~init:None ~f:(fun acc word -> Some begin match acc with | None -> ([], word) | Some (lines, line) -> (* efficiency is not a concern for the string lengths we expect *) let line_and_word = line ^ " " ^ word in if String.length line_and_word <= width then (lines, line_and_word) else (line :: lines, word) end) with | None -> [] | Some (lines, line) -> List.rev (line :: lines)) TEST_MODULE "word wrap" = struct TEST = word_wrap "" 10 = [] let short_word = "abcd" TEST = word_wrap short_word (String.length short_word) = [short_word] TEST = word_wrap "abc\ndef\nghi" 100 = ["abc"; "def"; "ghi"] let long_text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus \ fermentum condimentum eros, sit amet pulvinar dui ultrices in." TEST = word_wrap long_text 1000 = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus \ fermentum condimentum eros, sit amet pulvinar dui ultrices in."] TEST = word_wrap long_text 39 = (* .........1.........2.........3.........4 1234567890123456789012345678901234567890 *) ["Lorem ipsum dolor sit amet, consectetur"; "adipiscing elit. Vivamus fermentum"; "condimentum eros, sit amet pulvinar dui"; "ultrices in."] (* no guarantees: too-long words just overhang the soft bound *) TEST = word_wrap long_text 2 = ["Lorem"; "ipsum"; "dolor"; "sit"; "amet,"; "consectetur"; "adipiscing"; "elit."; "Vivamus"; "fermentum"; "condimentum"; "eros,"; "sit"; "amet"; "pulvinar"; "dui"; "ultrices"; "in."] end let to_string ts = let n = List.fold ts ~init:0 ~f:(fun acc t -> Int.max acc (String.length t.name)) in let num_cols = 80 in (* anything more dynamic is likely too brittle *) let extend x = let slack = n - String.length x in x ^ String.make slack ' ' in let lhs_width = n + 4 in let lhs_pad = String.make lhs_width ' ' in String.concat (List.map ts ~f:(fun t -> let rows k v = let vs = word_wrap v (num_cols - lhs_width) in match vs with | [] -> [" "; k; "\n"] | v :: vs -> let first_line = [" "; extend k; " "; v; "\n"] in let rest_lines = List.map vs ~f:(fun v -> [lhs_pad; v; "\n"]) in List.concat (first_line :: rest_lines) in String.concat (List.concat (rows t.name t.doc :: begin match t.aliases with | [] -> [] | [x] -> [rows "" (sprintf "(alias: %s)" x)] | xs -> [rows "" (sprintf "(aliases: %s)" (String.concat ~sep:", " xs))] end)))) end end (* universal maps are used to pass around values between different bits of command line parsing code without having a huge impact on the types involved 1. passing values from parsed args to command-line autocomplete functions 2. passing special values to a base commands that request them in their spec * expanded subcommand path * args passed to the base command * help text for the base command *) module Env = struct include Univ_map let key_create name = Univ_map.Key.create ~name sexp_of_opaque let multi_add = Univ_map.Multi.add let set_with_default = Univ_map.With_default.set end module Completer = struct type t = (Env.t -> part:string -> string list) option let run_and_exit t env ~part : never_returns = Option.iter t ~f:(fun completions -> List.iter ~f:print_endline (completions env ~part)); exit 0 end module Arg_type = struct type 'a t = { parse : string -> ('a, exn) Result.t; complete : Completer.t; key : 'a Univ_map.Multi.Key.t option; } let create ?complete ?key of_string = let parse x = Result.try_with (fun () -> of_string x) in { parse; key; complete } let string = create Fn.id let int = create Int.of_string let char = create Char.of_string let float = create Float.of_string let bool = create Bool.of_string let date = create Date.of_string let time = create Time.of_string_abs let time_ofday = create Time.Ofday.Zoned.of_string let time_ofday_unzoned = create Time.Ofday.of_string let time_span = create Time.Span.of_string let file ?key of_string = create ?key of_string ~complete:(fun _ ~part -> let prog = "bash" in let args = ["bash"; "-c"; "compgen -f $0"; part] in never_returns (Unix.exec ~prog ~args ())) let of_map ?key map = create ?key ~complete:(fun _ ~part:prefix -> List.filter_map (Map.to_alist map) ~f:(fun (name, _) -> if String.is_prefix name ~prefix then Some name else None)) (fun arg -> match Map.find map arg with | Some v -> v | None -> failwithf "valid arguments: {%s}" (String.concat ~sep:"," (Map.keys map)) ()) let of_alist_exn ?key alist = match String.Map.of_alist alist with | `Ok map -> of_map ?key map | `Duplicate_key key -> failwithf "Command.Spec.Arg_type.of_alist_exn: duplicate key %s" key () module Export = struct let string = string let int = int let char = char let float = float let bool = bool let date = date let time = time let time_ofday = time_ofday let time_ofday_unzoned = time_ofday_unzoned let time_span = time_span let file = file Fn.id end end module Flag = struct module Internal = struct type action = | No_arg of (Env.t -> Env.t) | Arg of (string -> Env.t -> Env.t) * Completer.t | Rest of (string list -> unit) type t = { name : string; aliases : string list; action : action; doc : string; check_available : [ `Optional | `Required of (unit -> unit) ]; name_matching : [`Prefix | `Full_match_required]; } let wrap_if_optional t x = match t.check_available with | `Optional -> sprintf "[%s]" x | `Required _ -> x module Deprecated = struct (* flag help in the format of the old command. used for injection *) let help ({name; doc; aliases; action=_; check_available=_; name_matching=_ } as t) = if String.is_prefix doc ~prefix:" " then (name, String.lstrip doc) :: List.map aliases ~f:(fun x -> (x, sprintf "same as \"%s\"" name)) else let (arg, doc) = match String.lsplit2 doc ~on:' ' with | None -> (doc, "") | Some pair -> pair in (wrap_if_optional t (name ^ " " ^ arg), String.lstrip doc) :: List.map aliases ~f:(fun x -> (wrap_if_optional t (x ^ " " ^ arg), sprintf "same as \"%s\"" name)) end let align ({name; doc; aliases; action=_; check_available=_; name_matching=_ } as t) = let (name, doc) = match String.lsplit2 doc ~on:' ' with | None | Some ("", _) -> (name, String.strip doc) | Some (arg, doc) -> (name ^ " " ^ arg, doc) in let name = wrap_if_optional t name in { Format.V1.name; doc; aliases} end type 'a state = { action : Internal.action; read : unit -> 'a; optional : bool; } type 'a t = string -> 'a state let arg_flag name arg_type read write ~optional = { read; optional; action = let update arg env = match arg_type.Arg_type.parse arg with | Error exn -> die "failed to parse %s value %S.\n%s" name arg (Exn.to_string exn) () | Ok arg -> write arg; match arg_type.Arg_type.key with | None -> env | Some key -> Env.multi_add env key arg in Arg (update, arg_type.Arg_type.complete); } let map_flag t ~f = fun input -> let {action; read; optional} = t input in { action; read = (fun () -> f (read ())); optional; } let write_option name v arg = match !v with | None -> v := Some arg | Some _ -> die "flag %s passed more than once" name () let required_value ?default arg_type name ~optional = let v = ref None in let read () = match !v with | Some v -> v | None -> match default with | Some v -> v | None -> die "missing required flag: %s" name () in let write arg = write_option name v arg in arg_flag name arg_type read write ~optional let required arg_type name = required_value arg_type name ~optional:false let optional_with_default default arg_type name = required_value ~default arg_type name ~optional:true let optional arg_type name = let v = ref None in let read () = !v in let write arg = write_option name v arg in arg_flag name arg_type read write ~optional:true let no_arg_general ~key_value ~deprecated_hook name = let v = ref false in let read () = !v in let write () = if !v then die "flag %s passed more than once" name () else v := true in let action env = let env = Option.fold key_value ~init:env ~f:(fun env (key, value) -> Env.set_with_default env key value) in write (); env in let action = match deprecated_hook with | None -> action | Some f -> (fun x -> let env = action x in f (); env ) in { read; action = No_arg action; optional = true } let no_arg name = no_arg_general name ~key_value:None ~deprecated_hook:None let no_arg_register ~key ~value name = no_arg_general name ~key_value:(Some (key, value)) ~deprecated_hook:None let listed arg_type name = let v = ref [] in let read () = List.rev !v in let write arg = v := arg :: !v in arg_flag name arg_type read write ~optional:true let one_or_more arg_type name = let q = Queue.create () in let read () = match Queue.to_list q with | first :: rest -> (first, rest) | [] -> die "missing required flag: %s" name () in let write arg = Queue.enqueue q arg in arg_flag name arg_type read write ~optional:false let escape_general ~deprecated_hook _name = let cell = ref None in let action = (fun cmd_line -> cell := Some cmd_line) in let read () = !cell in let action = match deprecated_hook with | None -> action | Some f -> (fun x -> f x; action x ) in { action = Rest action; read; optional = true } let no_arg_abort ~exit _name = { action = No_arg (fun _ -> never_returns (exit ())); optional = true; read = (fun () -> ()); } let escape name = escape_general ~deprecated_hook:None name module Deprecated = struct let no_arg ~hook name = no_arg_general ~deprecated_hook:(Some hook) ~key_value:None name let escape ~hook = escape_general ~deprecated_hook:(Some hook) end end module Path : sig type t val empty : t val root : string -> t val add : t -> subcommand:string -> t val commands : t -> string list val to_string : t -> string val to_string_dots : t -> string val pop_help : t -> t val length : t -> int end = struct type t = string list let empty = [] let root cmd = [Filename.basename cmd] let add t ~subcommand = subcommand :: t let commands t = List.rev t let to_string t = unwords (commands t) let length = List.length let pop_help = function | "help" :: t -> t | _ -> assert false let to_string_dots t = let t = match t with | [] -> [] | last :: init -> last :: List.map init ~f:(Fn.const ".") in to_string t end module Anons = struct module Grammar : sig type t val zero : t val one : string -> t val many : t -> t val maybe : t -> t val concat : t list -> t val usage : t -> string val ad_hoc : usage:string -> t end = struct type s = { usage : string; number : [`One | `Fixed | `Variable] } type t = s option let usage = function | None -> "" | Some s -> s.usage let zero = None let one name = Some { usage = name; number = `One } let many = function | None -> None (* strange, but not non-sense *) | Some s -> match s.number with | `Variable -> failwithf "iteration of variable-length grammars such as %s is disallowed" s.usage () | (`One | `Fixed) as g -> let s_usage = match g with | `One -> s.usage | `Fixed -> sprintf "(%s)" s.usage in Some { usage = sprintf "[%s ...]" s_usage; number = `Variable } let maybe = function | None -> None (* strange, but not non-sense *) | Some s -> Some { usage = sprintf "[%s]" s.usage; number = `Variable } let concat2 t1 t2 = match (t1, t2) with | (None, t) | (t, None) -> t | (Some s1, Some s2) -> let combined_usage = s1.usage ^ " " ^ s2.usage in match s1.number with | `Variable -> failwithf "the grammar %s for anonymous arguments \ is not supported because there is the possibility for \ arguments (%s) following a variable number of \ arguments (%s). Supporting such grammars would complicate \ the implementation significantly." combined_usage s2.usage s1.usage () | `One | `Fixed -> Some { usage = combined_usage; number = match s2.number with | `Variable -> `Variable; | `One | `Fixed -> `Fixed } let rec concat = function | [] -> zero | t :: ts -> concat2 t (concat ts) let ad_hoc ~usage = Some { usage ; number = `Variable } end module Parser : sig type 'a t val one : name:string -> 'a Arg_type.t -> 'a t val maybe : 'a t -> 'a option t val sequence : 'a t -> 'a list t val final_value : 'a t -> 'a val consume : 'a t -> string -> for_completion:bool -> (Env.t -> Env.t) * 'a t val complete : 'a t -> Env.t -> part:string -> never_returns module For_opening : sig val return : 'a -> 'a t val (<*>) : ('a -> 'b) t -> 'a t -> 'b t val (>>|) : 'a t -> ('a -> 'b) -> 'b t end end = struct type 'a t = | Done of 'a | More of 'a more (* A [Test] will (generally) return a [Done _] value if there is no more input and a [More] parser to use if there is any more input. *) | Test of (more:bool -> 'a t) (* If we're only completing, we can't pull values out, but we can still step through [t]s (which may have completion set up). *) | Only_for_completion of packed list and 'a more = { name : string; parse : string -> for_completion:bool -> (Env.t -> Env.t) * 'a t; complete : Completer.t; } and packed = Packed : 'a t -> packed let return a = Done a let pack_for_completion = function | Done _ -> [] (* won't complete or consume anything *) | More _ | Test _ as x -> [Packed x] | Only_for_completion ps -> ps let rec (<*>) tf tx = match tf with | Done f -> begin match tx with | Done x -> Done (f x) | Test test -> Test (fun ~more -> tf <*> test ~more) | More {name; parse; complete} -> let parse arg ~for_completion = let (upd, tx') = parse arg ~for_completion in (upd, tf <*> tx') in More {name; parse; complete} | Only_for_completion packed -> Only_for_completion packed end | Test test -> Test (fun ~more -> test ~more <*> tx) | More {name; parse; complete} -> let parse arg ~for_completion = let (upd, tf') = parse arg ~for_completion in (upd, tf' <*> tx) in More {name; parse; complete} | Only_for_completion packed -> Only_for_completion (packed @ pack_for_completion tx) let (>>|) t f = return f <*> t let one_more ~name {Arg_type.complete; parse = of_string; key} = let parse anon ~for_completion = match of_string anon with | Error exn -> if for_completion then (* we don't *really* care about this value, so just put in a dummy value so completion can continue *) (Fn.id, Only_for_completion []) else die "failed to parse %s value %S\n%s" name anon (Exn.to_string exn) () | Ok v -> let update env = Option.fold key ~init:env ~f:(fun env key -> Env.multi_add env key v) in (update, Done v) in More {name; parse; complete} let one ~name arg_type = Test (fun ~more -> if more then one_more ~name arg_type else die "missing anonymous argument: %s" name ()) let maybe t = Test (fun ~more -> if more then t >>| fun a -> Some a else return None) let sequence t = let rec loop = Test (fun ~more -> if more then return (fun v acc -> v :: acc) <*> t <*> loop else return []) in loop let rec final_value = function | Done a -> a | Test f -> final_value (f ~more:false) | More {name; _} -> die "missing anonymous argument: %s" name () | Only_for_completion _ -> failwith "BUG: asked for final value when doing completion" let rec consume : type a . a t -> string -> for_completion:bool -> ((Env.t -> Env.t) * a t) = fun t arg ~for_completion -> match t with | Done _ -> die "too many anonymous arguments" () | Test f -> consume (f ~more:true) arg ~for_completion | More {parse; _} -> parse arg ~for_completion | Only_for_completion packed -> match packed with | [] -> (Fn.id, Only_for_completion []) | (Packed t) :: rest -> let (upd, t) = consume t arg ~for_completion in (upd, Only_for_completion (pack_for_completion t @ rest)) let rec complete : type a . a t -> Env.t -> part:string -> never_returns = fun t env ~part -> match t with | Done _ -> exit 0 | Test f -> complete (f ~more:true) env ~part | More {complete; _} -> Completer.run_and_exit complete env ~part | Only_for_completion t -> match t with | [] -> exit 0 | (Packed t) :: _ -> complete t env ~part module For_opening = struct let return = return let (<*>) = (<*>) let (>>|) = (>>|) end end open Parser.For_opening type 'a t = { p : 'a Parser.t; grammar : Grammar.t; } let t2 t1 t2 = { p = return (fun a1 a2 -> (a1, a2)) <*> t1.p <*> t2.p ; grammar = Grammar.concat [t1.grammar; t2.grammar]; } let t3 t1 t2 t3 = { p = return (fun a1 a2 a3 -> (a1, a2, a3)) <*> t1.p <*> t2.p <*> t3.p ; grammar = Grammar.concat [t1.grammar; t2.grammar; t3.grammar]; } let t4 t1 t2 t3 t4 = { p = return (fun a1 a2 a3 a4 -> (a1, a2, a3, a4)) <*> t1.p <*> t2.p <*> t3.p <*> t4.p ; grammar = Grammar.concat [t1.grammar; t2.grammar; t3.grammar; t4.grammar]; } let normalize str = (* Verify the string is not empty or surrounded by whitespace *) let strlen = String.length str in if strlen = 0 then failwith "Empty anonymous argument name provided"; if String.(<>) (String.strip str) str then failwithf "argument name %S has surrounding whitespace" str (); (* If the string contains special surrounding characters, don't do anything *) let has_special_chars = let special_chars = Char.Set.of_list ['<'; '>'; '['; ']'; '('; ')'; '{'; '}'] in String.exists str ~f:(Set.mem special_chars) in if has_special_chars then str else String.uppercase str TEST = String.equal (normalize "file") "FILE" TEST = String.equal (normalize "FiLe") "FILE" TEST = String.equal (normalize "") "" TEST = String.equal (normalize "(FiLe)") "(FiLe)" TEST = String.equal (normalize "[FiLe]") "[FiLe]" TEST = String.equal (normalize "{FiLe}") "{FiLe}" TEST = String.equal (normalize "a") "a" TEST = try ignore (normalize "" ); false with _ -> true TEST = try ignore (normalize " file " ); false with _ -> true TEST = try ignore (normalize "file " ); false with _ -> true TEST = try ignore (normalize " file" ); false with _ -> true let (%:) name arg_type = let name = normalize name in { p = Parser.one ~name arg_type; grammar = Grammar.one name; } let map_anons t ~f = { p = t.p >>| f; grammar = t.grammar; } let maybe t = { p = Parser.maybe t.p; grammar = Grammar.maybe t.grammar; } let maybe_with_default default t = let t = maybe t in { t with p = t.p >>| fun v -> Option.value ~default v } let sequence t = { p = Parser.sequence t.p; grammar = Grammar.many t.grammar; } let non_empty_sequence t = t2 t (sequence t) module Deprecated = struct let ad_hoc ~usage_arg = { p = Parser.sequence (Parser.one ~name:"WILL NEVER BE PRINTED" Arg_type.string); grammar = Grammar.ad_hoc ~usage:usage_arg } end end module Cmdline = struct type t = Nil | Cons of string * t | Complete of string let of_list args = List.fold_right args ~init:Nil ~f:(fun arg args -> Cons (arg, args)) let rec to_list = function | Nil -> [] | Cons (x, xs) -> x :: to_list xs | Complete x -> [x] let rec ends_in_complete = function | Complete _ -> true | Nil -> false | Cons (_, args) -> ends_in_complete args let extend t ~extend ~path = if ends_in_complete t then t else begin let path_list = Option.value ~default:[] (List.tl (Path.commands path)) in of_list (to_list t @ extend path_list) end end TEST_MODULE "Cmdline.extend" = struct let path_of_list subcommands = List.fold subcommands ~init:(Path.root "exe") ~f:(fun path subcommand -> Path.add path ~subcommand) let extend path = match path with | ["foo"; "bar"] -> ["-foo"; "-bar"] | ["foo"; "baz"] -> ["-foobaz"] | _ -> ["default"] let test path args expected = let expected = Cmdline.of_list expected in let observed = let path = path_of_list path in let args = Cmdline.of_list args in Cmdline.extend args ~extend ~path in Pervasives.(=) expected observed TEST = test ["foo"; "bar"] ["anon"; "-flag"] ["anon"; "-flag"; "-foo"; "-bar"] TEST = test ["foo"; "baz"] [] ["-foobaz"] TEST = test ["zzz"] ["x"; "y"; "z"] ["x"; "y"; "z"; "default"] end module Key_type = struct type t = Subcommand | Flag let to_string = function | Subcommand -> "subcommand" | Flag -> "flag" end let assert_no_underscores key_type flag_or_subcommand = if String.exists flag_or_subcommand ~f:(fun c -> c = '_') then failwithf "%s %s contains an underscore. Use a dash instead." (Key_type.to_string key_type) flag_or_subcommand () let normalize key_type key = assert_no_underscores key_type key; match key_type with | Key_type.Flag -> if String.equal key "-" then failwithf "invalid key name: %S" key (); if String.is_prefix ~prefix:"-" key then key else "-" ^ key | Key_type.Subcommand -> String.lowercase key let lookup_expand alist prefix key_type = match List.filter alist ~f:(function | (key, (_, `Full_match_required)) -> String.(=) key prefix | (key, (_, `Prefix)) -> String.is_prefix key ~prefix) with | [(key, (data, _name_matching))] -> Ok (key, data) | [] -> Error (sprintf !"unknown %{Key_type} %s" key_type prefix) | matches -> match List.find matches ~f:(fun (key, _) -> String.(=) key prefix) with | Some (key, (data, _name_matching)) -> Ok (key, data) | None -> let matching_keys = List.map ~f:fst matches in Error (sprintf !"%{Key_type} %s is an ambiguous prefix: %s" key_type prefix (String.concat ~sep:", " matching_keys)) let lookup_expand_with_aliases map prefix key_type = let alist = List.concat_map (String.Map.data map) ~f:(fun flag -> let { Flag.Internal. name; aliases; action=_; doc=_; check_available=_; name_matching } = flag in let data = (flag, name_matching) in (name, data) :: List.map aliases ~f:(fun alias -> (alias, data))) in match List.find_a_dup alist ~compare:(fun (s1, _) (s2, _) -> String.compare s1 s2) with | None -> lookup_expand alist prefix key_type | Some (flag, _) -> failwithf "multiple flags named %s" flag () module Base = struct type t = { summary : string; readme : (unit -> string) option; flags : Flag.Internal.t String.Map.t; anons : Env.t -> ([`Parse_args] -> [`Run_main] -> unit) Anons.Parser.t; usage : Anons.Grammar.t; } module Deprecated = struct let subcommand_cmp_fst (a, _) (c, _) = help_screen_compare a c let flags_help ?(display_help_flags = true) t = let flags = String.Map.data t.flags in let flags = if display_help_flags then flags else List.filter flags ~f:(fun f -> f.name <> "-help") in List.concat_map ~f:Flag.Internal.Deprecated.help flags end let formatted_flags t = String.Map.data t.flags |> List.map ~f:Flag.Internal.align (* this sort puts optional flags after required ones *) |> List.sort ~cmp:(fun a b -> String.compare a.Format.V1.name b.name) |> Format.V1.sort let help_text ~path t = unparagraphs (List.filter_opt [ Some t.summary; Some (" " ^ Path.to_string path ^ " " ^ Anons.Grammar.usage t.usage); Option.map t.readme ~f:(fun readme -> readme ()); Some "=== flags ==="; Some (Format.V1.to_string (formatted_flags t)); ]) module Sexpable = struct module V1 = struct type t = { summary : string; readme : string sexp_option; usage : string; flags : Format.V1.t list; } with sexp end include V1 end let to_sexpable t = { Sexpable. summary = t.summary; readme = Option.map t.readme ~f:(fun readme -> readme ()); usage = Anons.Grammar.usage t.usage; flags = formatted_flags t; } let path_key = Env.key_create "path" let args_key = Env.key_create "args" let help_key = Env.key_create "help" let run t env ~path ~args = let help_text = lazy (help_text ~path t) in let env = Env.set env path_key path in let env = Env.set env args_key (Cmdline.to_list args) in let env = Env.set env help_key help_text in let rec loop env anons = function | Cmdline.Nil -> List.iter (String.Map.data t.flags) ~f:(fun flag -> match flag.check_available with | `Optional -> () | `Required check -> check ()); Anons.Parser.final_value anons | Cons (arg, args) -> if String.is_prefix arg ~prefix:"-" && not (String.equal arg "-") (* support the convention where "-" means stdin *) then begin let flag = arg in let (flag, { Flag.Internal. action; name=_; aliases=_; doc=_; check_available=_; name_matching=_ }) = match lookup_expand_with_aliases t.flags flag Key_type.Flag with | Error msg -> die "%s" msg () | Ok x -> x in match action with | No_arg f -> let env = f env in loop env anons args | Arg (f, comp) -> begin match args with | Nil -> die "missing argument for flag %s" flag () | Cons (arg, rest) -> let env = try f arg env with | Failed_to_parse_command_line _ as e -> if Cmdline.ends_in_complete rest then env else raise e in loop env anons rest | Complete part -> never_returns (Completer.run_and_exit comp env ~part) end | Rest f -> if Cmdline.ends_in_complete args then exit 0; f (Cmdline.to_list args); loop env anons Nil end else begin let (env_upd, anons) = Anons.Parser.consume anons arg ~for_completion:(Cmdline.ends_in_complete args) in let env = env_upd env in loop env anons args end | Complete part -> if String.is_prefix part ~prefix:"-" then begin List.iter (String.Map.keys t.flags) ~f:(fun name -> if String.is_prefix name ~prefix:part then print_endline name); exit 0 end else never_returns (Anons.Parser.complete anons env ~part); in match Result.try_with (fun () -> loop env (t.anons env) args `Parse_args) with | Ok thunk -> thunk `Run_main | Error exn -> match exn with | Failed_to_parse_command_line _ when Cmdline.ends_in_complete args -> exit 0 | Failed_to_parse_command_line msg -> print_endline (Lazy.force help_text); prerr_endline msg; exit 1 | _ -> print_endline (Lazy.force help_text); raise exn module Spec = struct type ('a, 'b) t = { f : Env.t -> ('a -> 'b) Anons.Parser.t; usage : unit -> Anons.Grammar.t; flags : unit -> Flag.Internal.t list; } (* the reason that [param] is defined in terms of [t] rather than the other way round is that the delayed evaluation matters for sequencing of read/write operations on ref cells in the representation of flags *) type 'a param = { param : 'm. ('a -> 'm, 'm) t } open Anons.Parser.For_opening let app t1 t2 ~f = { f = (fun env -> return f <*> t1.f env <*> t2.f env ); flags = (fun () -> t2.flags () @ t1.flags ()); usage = (fun () -> Anons.Grammar.concat [t1.usage (); t2.usage ()]); } (* So sad. We can't define [apply] in terms of [app] because of the value restriction. *) let apply pf px = { param = { f = (fun env -> return (fun mf mx k -> mf (fun f -> (mx (fun x -> k (f x))))) <*> pf.param.f env <*> px.param.f env ); flags = (fun () -> px.param.flags () @ pf.param.flags ()); usage = (fun () -> Anons.Grammar.concat [pf.param.usage (); px.param.usage ()]); } } let (++) t1 t2 = app t1 t2 ~f:(fun f1 f2 x -> f2 (f1 x)) let (+>) t1 p2 = app t1 p2.param ~f:(fun f1 f2 x -> f2 (f1 x)) let (+<) t1 p2 = app p2.param t1 ~f:(fun f2 f1 x -> f1 (f2 x)) let step f = { f = (fun _env -> return f); flags = (fun () -> []); usage = (fun () -> Anons.Grammar.zero); } let empty : 'm. ('m, 'm) t = { f = (fun _env -> return Fn.id); flags = (fun () -> []); usage = (fun () -> Anons.Grammar.zero); } let const v = { param = { f = (fun _env -> return (fun k -> k v)); flags = (fun () -> []); usage = (fun () -> Anons.Grammar.zero); } } let map p ~f = { param = { f = (fun env -> p.param.f env >>| fun c k -> c (fun v -> k (f v))); flags = p.param.flags; usage = p.param.usage; } } let wrap f t = { f = (fun env -> t.f env >>| fun run main -> f ~run ~main); flags = t.flags; usage = t.usage; } let of_params params = let t = params.param in { f = (fun env -> t.f env >>| fun run main -> run Fn.id main); flags = t.flags; usage = t.usage; } let lookup key = { param = { f = (fun env -> return (fun m -> m (Env.find_exn env key))); flags = (fun () -> []); usage = (fun () -> Anons.Grammar.zero); } } let path : Path.t param = lookup path_key let args : string list param = lookup args_key let help : string Lazy.t param = lookup help_key let env = { param = { f = (fun env -> return (fun m -> m env)); flags = (fun () -> []); usage = (fun () -> Anons.Grammar.zero); } } include struct module Arg_type = Arg_type include Arg_type.Export end include struct open Anons type 'a anons = 'a t let (%:) = (%:) let map_anons = map_anons let maybe = maybe let maybe_with_default = maybe_with_default let sequence = sequence let non_empty_sequence = non_empty_sequence let t2 = t2 let t3 = t3 let t4 = t4 let anon spec = { param = { f = (fun _env -> spec.p >>| fun v k -> k v); flags = (fun () -> []); usage = (fun () -> spec.grammar); } } end include struct open Flag type 'a flag = 'a t let map_flag = map_flag let escape = escape let listed = listed let one_or_more = one_or_more let no_arg = no_arg let no_arg_register = no_arg_register let no_arg_abort = no_arg_abort let optional = optional let optional_with_default = optional_with_default let required = required let flag ?(aliases = []) ?full_flag_required name mode ~doc = let normalize flag = normalize Key_type.Flag flag in let name = normalize name in let aliases = List.map ~f:normalize aliases in let {read; action; optional} = mode name in let check_available = if optional then `Optional else `Required (fun () -> ignore (read ())) in let name_matching = if Option.is_some full_flag_required then `Full_match_required else `Prefix in { param = { f = (fun _env -> return (fun k -> k (read ()))); flags = (fun () -> [{ name; aliases; doc; action; check_available; name_matching }]); usage = (fun () -> Anons.Grammar.zero); } } include Applicative.Make (struct type nonrec 'a t = 'a param let return = const let apply = apply let map = `Custom map end) let pair = both end let flags_of_args_exn args = List.fold args ~init:empty ~f:(fun acc (name, spec, doc) -> let gen f flag_type = step (fun m x -> f x; m) +> flag name flag_type ~doc in let call f arg_type = gen (fun x -> Option.iter x ~f) (optional arg_type) in let set r arg_type = call (fun x -> r := x) arg_type in let set_bool r b = gen (fun passed -> if passed then r := b) no_arg in acc ++ begin match spec with | Arg.Unit f -> gen (fun passed -> if passed then f ()) no_arg | Arg.Set r -> set_bool r true | Arg.Clear r -> set_bool r false | Arg.String f -> call f string | Arg.Set_string r -> set r string | Arg.Int f -> call f int | Arg.Set_int r -> set r int | Arg.Float f -> call f float | Arg.Set_float r -> set r float | Arg.Bool f -> call f bool | Arg.Symbol (syms, f) -> let arg_type = Arg_type.of_alist_exn (List.map syms ~f:(fun sym -> (sym, sym))) in call f arg_type | Arg.Rest f -> gen (fun x -> Option.iter x ~f:(List.iter ~f)) escape | Arg.Tuple _ -> failwith "Arg.Tuple is not supported by Command.Spec.flags_of_args_exn" end) module Deprecated = struct include Flag.Deprecated include Anons.Deprecated end end end let group_or_exec_help_text ~show_flags ~path ~summary ~readme ~format_list = unparagraphs (List.filter_opt [ Some summary; Some (String.concat [" "; Path.to_string path; " SUBCOMMAND"]); Option.map readme ~f:(fun readme -> readme ()); Some (if show_flags then "=== subcommands and flags ===" else "=== subcommands ==="); Some (Format.V1.to_string format_list); ]) ;; module Group = struct type 'a t = { summary : string; readme : (unit -> string) option; subcommands : (string * 'a) list; body : (path:string list -> unit) option; } let help_text ~show_flags ~to_format_list ~path t = group_or_exec_help_text ~show_flags ~path ~readme:t.readme ~summary:t.summary ~format_list:(to_format_list t) ;; module Sexpable = struct module V1 = struct type 'a t = { summary : string; readme : string sexp_option; subcommands : (string, 'a) List.Assoc.t; } with sexp end include V1 end let to_sexpable ~subcommand_to_sexpable t = { Sexpable. summary = t.summary; readme = Option.map ~f:(fun readme -> readme ()) t.readme; subcommands = List.Assoc.map ~f:subcommand_to_sexpable t.subcommands; } end module Exec = struct type t = { summary : string; readme : (unit -> string) option; path_to_exe : string; path_to_subcommand : string list; (* only used internally *) } module Sexpable = struct module V1 = struct type t = { summary : string; readme : string sexp_option; path_to_exe : string; } with sexp end include V1 end let to_sexpable t = { Sexpable. summary = t.summary; readme = Option.map ~f:(fun readme -> readme ()) t.readme; path_to_exe = t.path_to_exe; } let exec_with_args t ~args = let prog = t.path_to_exe in never_returns (Unix.exec ~prog ~args:(prog :: t.path_to_subcommand @ args) ()) ;; let help_text ~show_flags ~to_format_list ~path t = group_or_exec_help_text ~show_flags ~path ~readme:(t.readme) ~summary:(t.summary) ~format_list:(to_format_list t) ;; end type t = | Base of Base.t | Group of t Group.t | Exec of Exec.t module Sexpable = struct let supported_versions : int Queue.t = Queue.create () let add_version n = Queue.enqueue supported_versions n module V1 = struct let () = add_version 1 type t = | Base of Base.Sexpable.V1.t | Group of t Group.Sexpable.V1.t | Exec of Exec.Sexpable.V1.t with sexp let to_latest = Fn.id end module Internal : sig type t with sexp val of_latest : V1.t -> t val to_latest : t -> V1.t end = struct type t = | V1 of V1.t with sexp let of_latest t = V1 t let to_latest = function | V1 t -> V1.to_latest t end include V1 module Latest = V1 let supported_versions = Int.Set.of_list (Queue.to_list supported_versions) include Sexpable.Of_sexpable (Internal) (struct type t = V1.t let to_sexpable = Internal.of_latest let of_sexpable = Internal.to_latest end) let get_summary = function | Base x -> x.summary | Group x -> x.summary | Exec x -> x.summary let get_readme = function | Base x -> x.readme | Group x -> x.readme | Exec x -> x.readme let extraction_var = "COMMAND_OUTPUT_HELP_SEXP" let of_external ~path_to_exe = let process_info = Unix.create_process_env () ~prog:path_to_exe ~args:[] ~env:(`Extend [ ( extraction_var , supported_versions |> Int.Set.sexp_of_t |> Sexp.to_string ) ]) in (* We aren't writing to the process's stdin or reading from the process's stderr, so close them early. That way if we open a process that isn't behaving how we expect, it at least won't block on these file descriptors. *) Unix.close process_info.stdin; Unix.close process_info.stderr; let t = process_info.stdout |> Unix.in_channel_of_descr |> In_channel.input_all |> String.strip |> Sexp.of_string |> t_of_sexp in Unix.close process_info.stdout; ignore (Unix.wait (`Pid process_info.pid)); t let rec find (t : t) ~path_to_subcommand = match path_to_subcommand with | [] -> t | sub :: subs -> match t with | Base _ -> failwithf "unexpected subcommand %S" sub () | Exec {path_to_exe; _} -> find (of_external ~path_to_exe) ~path_to_subcommand:(sub :: subs) | Group g -> match List.Assoc.find g.subcommands sub with | None -> failwithf "unknown subcommand %S" sub () | Some t -> find t ~path_to_subcommand:subs end let rec to_sexpable = function | Base base -> Sexpable.Base (Base.to_sexpable base) | Exec exec -> Sexpable.Exec (Exec.to_sexpable exec) | Group group -> Sexpable.Group (Group.to_sexpable ~subcommand_to_sexpable:to_sexpable group) type ('main, 'result) basic_command = summary:string -> ?readme:(unit -> string) -> ('main, unit -> 'result) Base.Spec.t -> 'main -> t let get_summary = function | Base base -> base.Base.summary | Group group -> group.Group.summary | Exec exec -> exec.Exec.summary let extend_exn ~mem ~add map key_type ~key data = if mem map key then failwithf "there is already a %s named %s" (Key_type.to_string key_type) key (); add map ~key ~data let extend_map_exn map key_type ~key data = extend_exn map key_type ~key data ~mem:Map.mem ~add:Map.add let extend_alist_exn alist key_type ~key data = extend_exn alist key_type ~key data ~mem:(fun alist key -> List.Assoc.mem alist key ~equal:String.equal) ~add:(fun alist ~key ~data -> List.Assoc.add alist key data ~equal:String.equal) module Bailout_dump_flag = struct let add base ~name ~aliases ~text ~text_summary = let flags = base.Base.flags in let flags = extend_map_exn flags Key_type.Flag ~key:name { name; aliases; check_available = `Optional; action = No_arg (fun env -> print_endline (text env); exit 0); doc = sprintf " print %s and exit" text_summary; name_matching = `Prefix; } in { base with Base.flags } end let basic ~summary ?readme {Base.Spec.usage; flags; f} main = let flags = flags () in let usage = usage () in let anons env = let open Anons.Parser.For_opening in f env >>| fun k `Parse_args -> let thunk = k main in fun `Run_main -> thunk () in let flags = match String.Map.of_alist (List.map flags ~f:(fun flag -> (flag.name, flag))) with | `Duplicate_key flag -> failwithf "multiple flags named %s" flag () | `Ok map -> begin (* check for alias collision, too *) match String.Map.of_alist (List.concat_map flags ~f:(fun { name; aliases; action = _; doc = _; check_available = _; name_matching = _ } -> (name, ()) :: List.map aliases ~f:(fun alias -> (alias, ())))) with | `Duplicate_key x -> failwithf "multiple flags or aliases named %s" x () | `Ok _ -> () end; map in let base = { Base.summary; readme; usage; flags; anons } in let base = Bailout_dump_flag.add base ~name:"-help" ~aliases:["-?"] ~text_summary:"this help text" ~text:(fun env -> Lazy.force (Env.find_exn env Base.help_key)) in Base base let subs_key : (string * t) list Env.Key.t = Env.key_create "subcommands" let gather_help ~recursive ~show_flags ~expand_dots sexpable = let rec loop rpath acc sexpable = let string_of_path = if expand_dots then Path.to_string else Path.to_string_dots in let gather_exec rpath acc exec = loop rpath acc (Sexpable.of_external ~path_to_exe:exec.Exec.Sexpable.path_to_exe) in let gather_group rpath acc subs = let subs = if recursive && rpath <> Path.empty then List.Assoc.remove ~equal:String.(=) subs "help" else subs in let alist = List.stable_sort subs ~cmp:(fun a b -> help_screen_compare (fst a) (fst b)) in List.fold alist ~init:acc ~f:(fun acc (subcommand, t) -> let rpath = Path.add rpath ~subcommand in let key = string_of_path rpath in let doc = Sexpable.get_summary t in let acc = Fqueue.enqueue acc { Format.V1. name = key; doc; aliases = [] } in if recursive then loop rpath acc t else acc) in match sexpable with | Sexpable.Exec exec -> gather_exec rpath acc exec | Sexpable.Group group -> gather_group rpath acc group.Group.Sexpable.subcommands | Sexpable.Base base -> if show_flags then begin base.Base.Sexpable.flags |> List.filter ~f:(fun fmt -> fmt.Format.V1.name <> "[-help]") |> List.fold ~init:acc ~f:(fun acc fmt -> let rpath = Path.add rpath ~subcommand:fmt.Format.V1.name in let fmt = { fmt with Format.V1.name = string_of_path rpath } in Fqueue.enqueue acc fmt) end else acc in loop Path.empty Fqueue.empty sexpable ;; let help_subcommand ~summary ~readme = basic ~summary:"explain a given subcommand (perhaps recursively)" Base.Spec.( empty +> flag "-recursive" no_arg ~doc:" show subcommands of subcommands, etc." +> flag "-flags" no_arg ~doc:" show flags as well in recursive help" +> flag "-expand-dots" no_arg ~doc:" expand subcommands in recursive help" +> path +> env +> anon (maybe ("SUBCOMMAND" %: string)) ) (fun recursive show_flags expand_dots path (env : Env.t) cmd_opt () -> let subs = match Env.find env subs_key with | Some subs -> subs | None -> assert false (* maintained by [dispatch] *) in let path = let path = Path.pop_help path in Option.fold cmd_opt ~init:path ~f:(fun path subcommand -> Path.add path ~subcommand) in let group_help_text group = let to_format_list g = gather_help ~recursive ~show_flags ~expand_dots (to_sexpable (Group g)) |> Fqueue.to_list in Group.help_text ~show_flags ~to_format_list ~path group in let exec_help_text exec = let to_format_list e = gather_help ~recursive ~show_flags ~expand_dots (to_sexpable (Exec e)) |> Fqueue.to_list in Exec.help_text ~show_flags ~to_format_list ~path exec in let text = match cmd_opt with | None -> group_help_text { readme; summary; subcommands = subs; body = None; } | Some cmd -> match List.Assoc.find subs cmd ~equal:String.equal with | None -> die "unknown subcommand %s for command %s" cmd (Path.to_string path) () | Some t -> match t with | Exec exec -> exec_help_text exec | Group group -> group_help_text group | Base base -> Base.help_text ~path base in print_endline text) let group ~summary ?readme ?preserve_subcommand_order ?body alist = let alist = List.map alist ~f:(fun (name, t) -> (normalize Key_type.Subcommand name, t)) in let subcommands = match String.Map.of_alist alist with | `Duplicate_key name -> failwithf "multiple subcommands named %s" name () | `Ok map -> match preserve_subcommand_order with | Some () -> alist | None -> Map.to_alist map in Group {summary; readme; subcommands; body} let exec ~summary ?readme ~path_to_exe () = let path_to_exe = match path_to_exe with | `Absolute p -> if Filename.is_absolute p then p else failwith "Path passed to `Absolute must be absolute" | `Relative_to_me p -> if Filename.is_relative p then Filename.concat (Filename.dirname Sys.executable_name) p else failwith "Path passed to `Relative_to_me must be relative" in Exec {summary; readme; path_to_exe; path_to_subcommand = []} module Shape = struct type command = t type t = | Basic | Group of (string * command) list | Exec of (unit -> t) end let shape t : Shape.t = match t with | Base _ -> Basic | Group x -> Group x.subcommands | Exec {path_to_exe; path_to_subcommand; _} -> let rec loop ~path_to_exe ~path_to_subcommand : Shape.t = Exec (fun () -> match Sexpable.find (Sexpable.of_external ~path_to_exe) ~path_to_subcommand with | Base _ -> Basic | Exec {path_to_exe; _} -> loop ~path_to_exe ~path_to_subcommand:[] | Group x -> Group (List.map x.subcommands ~f:(fun (sub, fmt) -> ( sub , Exec { path_to_exe; path_to_subcommand = path_to_subcommand @ [sub]; summary = Sexpable.get_summary fmt; readme = Option.map ~f:Fn.const (Sexpable.get_readme fmt); })))) in loop ~path_to_exe ~path_to_subcommand module Version_info = struct let print_version ~version = (* [version] was space delimited at some point and newline delimited at another. We always print one (repo, revision) pair per line and ensure sorted order *) String.split version ~on:' ' |> List.concat_map ~f:(String.split ~on:'\n') |> List.sort ~cmp:String.compare |> List.iter ~f:print_endline let print_build_info ~build_info = print_endline build_info let command ~version ~build_info = basic ~summary:"print version information" Base.Spec.( empty +> flag "-version" no_arg ~doc:" print the version of this build" +> flag "-build-info" no_arg ~doc:" print build info for this build" ) (fun version_flag build_info_flag -> begin if build_info_flag then print_build_info ~build_info else if version_flag then print_version ~version else (print_build_info ~build_info; print_version ~version) end; exit 0) let add ~version ~build_info unversioned = match unversioned with | Base base -> let base = Bailout_dump_flag.add base ~name:"-version" ~aliases:[] ~text_summary:"the version of this build" ~text:(Fn.const version) in let base = Bailout_dump_flag.add base ~name:"-build-info" ~aliases:[] ~text_summary:"info about this build" ~text:(Fn.const build_info) in Base base | Group group -> let subcommands = extend_alist_exn group.Group.subcommands Key_type.Subcommand ~key:"version" (command ~version ~build_info) in Group { group with Group.subcommands } | Exec exec -> Exec exec end (* clear the setting of environment variable associated with command-line completion and recursive help so that subprocesses don't see them. *) let getenv_and_clear var = let value = Core_sys.getenv var in if Option.is_some value then Unix.unsetenv var; value ;; (* This script works in both bash (via readarray) and zsh (via read -A). If you change it, please test in both bash and zsh. It does not work in ksh (unexpected null byte) and tcsh (different function syntax). *) let dump_autocomplete_function () = let fname = sprintf "_jsautocom_%s" (Pid.to_string (Unix.getpid ())) in printf "function %s { export COMP_CWORD COMP_WORDS[0]=%s if type readarray > /dev/null then readarray -t COMPREPLY < <(\"${COMP_WORDS[@]}\") else IFS=\"\n\" read -d \"\x00\" -A COMPREPLY < <(\"${COMP_WORDS[@]}\") fi } complete -F %s %s %!" fname Sys.argv.(0) fname Sys.argv.(0) ;; let dump_help_sexp ~supported_versions t ~path_to_subcommand = Int.Set.inter Sexpable.supported_versions supported_versions |> Int.Set.max_elt |> function | None -> failwiths "Couldn't choose a supported help output version for Command.exec \ from the given supported versions." Sexpable.supported_versions Int.Set.sexp_of_t; | Some version_to_use -> assert (version_to_use = 1); (* for now, this is the only valid version *) to_sexpable t |> Sexpable.find ~path_to_subcommand |> Sexpable.sexp_of_t |> Sexp.to_string |> print_string ;; let handle_environment t ~argv = match argv with | [] -> failwith "missing executable name" | cmd :: args -> Option.iter (getenv_and_clear Sexpable.extraction_var) ~f:(fun version -> let supported_versions = Sexp.of_string version |> Int.Set.t_of_sexp in dump_help_sexp ~supported_versions t ~path_to_subcommand:args; exit 0); Option.iter (getenv_and_clear "COMMAND_OUTPUT_INSTALLATION_BASH") ~f:(fun _ -> dump_autocomplete_function (); exit 0); (cmd, args) ;; let set_comp_cword new_value = let new_value = Int.to_string new_value in Unix.putenv ~key:"COMP_CWORD" ~data:new_value ;; let process_args ~cmd ~args = let maybe_comp_cword = getenv_and_clear "COMP_CWORD" |> Option.map ~f:Int.of_string in let args = match maybe_comp_cword with | None -> Cmdline.of_list args | Some comp_cword -> let args = List.take (args @ [""]) comp_cword in List.fold_right args ~init:Cmdline.Nil ~f:(fun arg args -> match args with | Cmdline.Nil -> Cmdline.Complete arg | _ -> Cmdline.Cons (arg, args)) in (Path.root cmd, args, maybe_comp_cword) ;; let rec add_help_subcommands = function | Base _ as t -> t | Exec _ as t -> t | Group {summary; readme; subcommands; body} -> let subcommands = List.Assoc.map subcommands ~f:add_help_subcommands in let subcommands = extend_alist_exn subcommands Key_type.Subcommand ~key:"help" (help_subcommand ~summary ~readme) in Group {summary; readme; subcommands; body} ;; let maybe_apply_extend args ~extend ~path = Option.value_map extend ~default:args ~f:(fun f -> Cmdline.extend args ~extend:f ~path) ;; let rec dispatch t env ~extend ~path ~args ~maybe_new_comp_cword ~version ~build_info = let to_format_list (group : _ Group.t) : Format.V1.t list = let group = Group.to_sexpable ~subcommand_to_sexpable:to_sexpable group in List.map group.subcommands ~f:(fun (name, sexpable) -> { Format.V1. name; aliases = []; doc = Sexpable.get_summary sexpable }) |> Format.V1.sort in match t with | Base base -> let args = maybe_apply_extend args ~extend ~path in Base.run base env ~path ~args | Exec exec -> Option.iter ~f:set_comp_cword maybe_new_comp_cword; let args = Cmdline.to_list (maybe_apply_extend args ~extend ~path) in Exec.exec_with_args ~args exec | Group ({summary; readme; subcommands = subs; body} as group) -> let env = Env.set env subs_key subs in let die_showing_help msg = if not (Cmdline.ends_in_complete args) then begin eprintf "%s\n%!" (Group.help_text ~to_format_list ~path ~show_flags:false {summary; readme; subcommands = subs; body}); die "%s" msg () end in match args with | Nil -> begin match body with | None -> die_showing_help (sprintf "missing subcommand for command %s" (Path.to_string path)) | Some body -> body ~path:(Path.commands path) end | Cons (sub, rest) -> let (sub, rest) = (* Match for flags recognized when subcommands are expected next *) match (sub, rest) with (* Recognized at the top level command only *) | ("-version", _) when Path.length path = 1 -> Version_info.print_version ~version; exit 0 | ("-build-info", _) when Path.length path = 1 -> Version_info.print_build_info ~build_info; exit 0 (* Recognized everywhere *) | ("-help", Nil) -> print_endline (Group.help_text ~to_format_list ~path ~show_flags:false {group with subcommands = subs}); exit 0 | ("-help", Cmdline.Cons (sub, rest)) -> (sub, Cmdline.Cons ("-help", rest)) | _ -> (sub, rest) in begin match lookup_expand (List.Assoc.map subs ~f:(fun x -> (x, `Prefix))) sub Subcommand with | Error msg -> die_showing_help msg | Ok (sub, t) -> dispatch t env ~extend ~path:(Path.add path ~subcommand:sub) ~args:rest ~maybe_new_comp_cword:(Option.map ~f:Int.pred maybe_new_comp_cword) ~version ~build_info end | Complete part -> let subs = List.map subs ~f:fst |> List.filter ~f:(fun name -> String.is_prefix name ~prefix:part) |> List.sort ~cmp:String.compare in List.iter subs ~f:print_endline; exit 0 ;; INCLUDE "core_config.mlh" let default_version,default_build_info = IFDEF BUILD_VERSION_UTIL THEN Version_util.version, Version_util.build_info ELSE "no version util", "no build info" ENDIF let run ?(version = default_version) ?(build_info = default_build_info) ?(argv=Array.to_list Sys.argv) ?extend t = Exn.handle_uncaught ~exit:true (fun () -> let t = Version_info.add t ~version ~build_info in let t = add_help_subcommands t in let (cmd, args) = handle_environment t ~argv in let (path, args, maybe_new_comp_cword) = process_args ~cmd ~args in try dispatch t Env.empty ~extend ~path ~args ~maybe_new_comp_cword ~version ~build_info with | Failed_to_parse_command_line msg -> if Cmdline.ends_in_complete args then exit 0 else begin prerr_endline msg; exit 1 end) ;; let summary = function | Base x -> x.summary | Group x -> x.summary | Exec x -> x.summary module Spec = struct include Base.Spec let path = map ~f:Path.commands path end module Deprecated = struct module Spec = Spec.Deprecated let summary = get_summary let get_flag_names = function | Base base -> base.Base.flags |> String.Map.keys | Group _ | Exec _ -> assert false let help_recursive ~cmd ~with_flags ~expand_dots t s = let rec help_recursive_rec ~cmd t s = let new_s = s ^ (if expand_dots then cmd else ".") ^ " " in match t with | Base base -> let base_help = s ^ cmd, summary (Base base) in if with_flags then base_help :: List.map ~f:(fun (flag, h) -> (new_s ^ flag, h)) (List.sort ~cmp:Base.Deprecated.subcommand_cmp_fst (Base.Deprecated.flags_help ~display_help_flags:false base)) else [base_help] | Group {summary; subcommands; readme = _; body = _} -> (s ^ cmd, summary) :: begin subcommands |> List.sort ~cmp:Base.Deprecated.subcommand_cmp_fst |> List.concat_map ~f:(fun (cmd', t) -> help_recursive_rec ~cmd:cmd' t new_s) end | Exec _exec -> (* Command.exec does not support deprecated commands *) [] in help_recursive_rec ~cmd t s let version = default_version let build_info = default_build_info let run t ~cmd ~args ~is_help ~is_help_rec ~is_help_rec_flags ~is_expand_dots = let path_strings = String.split cmd ~on: ' ' in let path = List.fold path_strings ~init:Path.empty ~f:(fun p subcommand -> Path.add p ~subcommand) in let args = if is_expand_dots then "-expand-dots" :: args else args in let args = if is_help_rec_flags then "-flags" :: args else args in let args = if is_help_rec then "-r" :: args else args in let args = if is_help then "-help" :: args else args in let args = Cmdline.of_list args in let t = add_help_subcommands t in dispatch t Env.empty ~path ~args ~extend:None ~maybe_new_comp_cword:None ~version ~build_info end (* testing claims made in the mli about order of evaluation and [flags_of_args_exn] *) TEST_MODULE "Command.Spec.flags_of_args_exn" = struct let args q = [ ( "flag1", Arg.Unit (fun () -> Queue.enqueue q 1), "enqueue 1"); ( "flag2", Arg.Unit (fun () -> Queue.enqueue q 2), "enqueue 2"); ( "flag3", Arg.Unit (fun () -> Queue.enqueue q 3), "enqueue 3"); ] let parse argv = let q = Queue.create () in let command = basic ~summary:"" (Spec.flags_of_args_exn (args q)) Fn.id in run ~argv command; Queue.to_list q TEST = parse ["foo.exe";"-flag1";"-flag2";"-flag3"] = [1;2;3] TEST = parse ["foo.exe";"-flag2";"-flag3";"-flag1"] = [1;2;3] TEST = parse ["foo.exe";"-flag3";"-flag2";"-flag1"] = [1;2;3] end (* NOTE: all that follows is simply namespace management boilerplate. This will go away once we re-work the internals of Command to use Applicative from the ground up. *) module Param = struct module type S = sig include Applicative.S val help : string Lazy.t t val path : string list t val args : string list t val flag : ?aliases:string list -> ?full_flag_required:unit -> string -> 'a Flag.t -> doc:string -> 'a t val anon : 'a Anons.t -> 'a t end module A = struct type 'a t = 'a Spec.param include Applicative.Make (struct type nonrec 'a t = 'a t let return = Spec.const let apply = Spec.apply let map = `Custom Spec.map end) end include A module Args = struct type ('a, 'b) t = ('a -> 'b) A.t let applyN t1 t2 = A.map2 t1 t2 ~f:(fun f k -> k f) let mapN ~f t = A.map t ~f:(fun k -> k f) let step t ~f = A.map t ~f:(fun g x -> g (f x)) let cons p t = A.map2 p t ~f:(fun a f k -> f (k a)) let (@>) = cons let nil = (* inlined [let nil = return Fn.id] b/c of the value restriction *) { Spec. param = { f = (fun _env -> Anons.Parser.For_opening.return (fun k -> k Fn.id)); flags = (fun () -> []); usage = (fun () -> Anons.Grammar.zero); }; } end include (Args : module type of Args with type ('a, 'b) t := ('a, 'b) Args.t) let help = Spec.help let path = Spec.path let args = Spec.args let flag = Spec.flag let anon = Spec.anon module Arg_type = Arg_type include Arg_type.Export include struct open Flag let listed = listed let no_arg = no_arg let no_arg_abort = no_arg_abort let no_arg_register = no_arg_register let one_or_more = one_or_more let optional = optional let optional_with_default = optional_with_default let required = required let escape = escape end include struct open Anons let (%:) = (%:) let maybe = maybe let maybe_with_default = maybe_with_default let non_empty_sequence = non_empty_sequence let sequence = sequence let t2 = t2 let t3 = t3 let t4 = t4 end end type ('main, 'result) basic_command' = summary : string -> ?readme : (unit -> string) -> ('main, unit -> 'result) Param.Args.t -> 'main -> t let basic' ~summary ?readme params main = basic ~summary ?readme Spec.(of_params params) main core-113.00.00/src/command.mli000066400000000000000000000533531256461075500157000ustar00rootroot00000000000000(** purely functional command line parsing *) open Core_kernel.Std (** {1 argument types} *) module Arg_type : sig type 'a t (** the type of a command line argument *) (** An argument type includes information about how to parse values of that type from the command line, and (optionally) how to auto-complete partial arguments of that type via bash's programmable TAB-completion. In addition to the argument prefix, autocompletion also has access to any previously parsed arguments in the form of a heterogeneous map into which previously parsed arguments may register themselves by providing a [Univ_map.Key] using the [~key] argument to [create]. If the [of_string] function raises an exception, command line parsing will be aborted and the exception propagated up to top-level and printed along with command-line help. *) val create : ?complete:(Univ_map.t -> part:string -> string list) -> ?key:'a Univ_map.Multi.Key.t -> (string -> 'a) -> 'a t (** an auto-completing Arg_type over a finite set of values *) val of_map : ?key:'a Univ_map.Multi.Key.t -> 'a String.Map.t -> 'a t (** convenience wrapper for [of_map]. Raises on duplicate keys *) val of_alist_exn : ?key:'a Univ_map.Multi.Key.t -> (string * 'a) list -> 'a t (** [file] defines an [Arg_type.t] that completes in the same way as [Command.Spec.file], but perhaps with a different type than [string] or with an autocompletion key. *) val file : ?key:'a Univ_map.Multi.Key.t -> (string -> 'a) -> 'a t (* values to include in other namespaces *) module Export : sig val string : string t (** Beware that an anonymous argument of type [int] cannot be specified as negative, as it is ambiguous whether -1 is a negative number or a flag. If you need to pass a negative number to your program, make it a parameter to a flag. *) val int : int t val char : char t val float : float t val bool : bool t val date : Date.t t (** [time] requires a time zone. *) val time : Time.t t val time_ofday : Time.Ofday.Zoned.t t (** Use [time_ofday_unzoned] only when time zone is implied somehow. *) val time_ofday_unzoned : Time.Ofday.t t val time_span : Time.Span.t t (* [file] uses bash autocompletion. *) val file : string t end end (** {1 flag specifications} *) module Flag : sig type 'a t (** required flags must be passed exactly once *) val required : 'a Arg_type.t -> 'a t (** optional flags may be passed at most once *) val optional : 'a Arg_type.t -> 'a option t (** [optional_with_default] flags may be passed at most once, and default to a given value *) val optional_with_default : 'a -> 'a Arg_type.t -> 'a t (** [listed] flags may be passed zero or more times *) val listed : 'a Arg_type.t -> 'a list t (** [one_or_more] flags must be passed one or more times *) val one_or_more : 'a Arg_type.t -> ('a * 'a list) t (** [no_arg] flags may be passed at most once. The boolean returned is true iff the flag is passed on the command line *) val no_arg : bool t (** [no_arg_register ~key ~value] is like [no_arg], but associates [value] with [key] in the in the auto-completion environment *) val no_arg_register : key:'a Univ_map.With_default.Key.t -> value:'a -> bool t (** [no_arg_abort ~exit] is like [no_arg], but aborts command-line parsing by calling [exit]. This flag type is useful for "help"-style flags that just print something and exit. *) val no_arg_abort : exit:(unit -> never_returns) -> unit t (** [escape] flags may be passed at most once. They cause the command line parser to abort and pass through all remaining command line arguments as the value of the flag. A standard choice of flag name to use with [escape] is ["--"]. *) val escape : string list option t end (** {1 anonymous argument specifications} *) module Anons : sig type 'a t (** a specification of some number of anonymous arguments *) (** [(name %: typ)] specifies a required anonymous argument of type [typ]. The [name] must not be surrounded by whitespace, if it is, an exn will be raised. If the [name] is surrounded by a special character pair (<>, \{\}, \[\] or (),) [name] will remain as-is, otherwise, [name] will be uppercased. In the situation where [name] is only prefixed or only suffixed by one of the special character pairs, or different pairs are used, (e.g. " 'a Arg_type.t -> 'a t (** [sequence anons] specifies a sequence of anonymous arguments. An exception will be raised if [anons] matches anything other than a fixed number of anonymous arguments *) val sequence : 'a t -> 'a list t (** [non_empty_sequence anons] is like [sequence anons] except an exception will be raised if there is not at least one anonymous argument given. *) val non_empty_sequence : 'a t -> ('a * 'a list) t (** [(maybe anons)] indicates that some anonymous arguments are optional *) val maybe : 'a t -> 'a option t (** [(maybe_with_default default anons)] indicates an optional anonymous argument with a default value *) val maybe_with_default : 'a -> 'a t -> 'a t (** [t2], [t3], and [t4] each concatenate multiple anonymous argument specs into a single one. The purpose of these combinators is to allow for optional sequences of anonymous arguments. Consider a command with usage: {v main.exe FOO [BAR BAZ] v} where the second and third anonymous arguments must either both be there or both not be there. This can be expressed as: {[ t2 ("FOO" %: foo) (maybe (t2 ("BAR" %: bar) ("BAZ" %: baz)))] ]} Sequences of 5 or more anonymous arguments can be built up using nested tuples: {[ maybe (t3 a b (t3 c d e)) ]} *) val t2 : 'a t -> 'b t -> ('a * 'b) t val t3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t val t4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t end (** {1 specification of command parameters} *) module Param : sig module type S = sig include Applicative.S (** {2 various internal values} *) val help : string Lazy.t t (** the help text for the command *) val path : string list t (** the subcommand path of the command *) val args : string list t (** the arguments passed to the command *) (** [flag name spec ~doc] specifies a command that, among other things, takes a flag named [name] on its command line. [doc] indicates the meaning of the flag. All flags must have a dash at the beginning of the name. If [name] is not prefixed by "-", it will be normalized to ["-" ^ name]. Unless [full_flag_required] is used, one doesn't have to pass [name] exactly on the command line, but only an unambiguous prefix of [name] (i.e., a prefix which is not a prefix of any other flag's name). NOTE: the [doc] for a flag which takes an argument should be of the form [arg_name ^ " " ^ description] where [arg_name] describes the argument and [description] describes the meaning of the flag. NOTE: flag names (including aliases) containing underscores will be rejected. Use dashes instead. NOTE: "-" by itself is an invalid flag name and will be rejected. *) val flag : ?aliases : string list -> ?full_flag_required : unit -> string -> 'a Flag.t -> doc : string -> 'a t (** [anon spec] specifies a command that, among other things, takes the anonymous arguments specified by [spec]. *) val anon : 'a Anons.t -> 'a t end include S (* values included for convenience so you can specify all command line parameters inside a single local open of [Param] *) module Args : Applicative.Args with type 'a arg := 'a t include module type of Args with type ('a, 'b) t := ('a, 'b) Args.t module Arg_type : module type of Arg_type with type 'a t = 'a Arg_type.t include module type of Arg_type.Export include module type of Flag with type 'a t := 'a Flag.t include module type of Anons with type 'a t := 'a Anons.t end (** {1 older interface for command-line specifications} *) module Spec : sig (** {1 command parameters} *) (** specification of an individual parameter to the command's main function *) type 'a param = 'a Param.t include Param.S with type 'a t := 'a param (** Superceded by [return], preserved for backwards compatibility *) val const : 'a -> 'a param (** Superceded by [both], preserved for backwards compatibility *) val pair : 'a param -> 'b param -> ('a * 'b) param (** {1 command specifications} *) (** composable command-line specifications *) type ('main_in, 'main_out) t (** Ultimately one forms a basic command by combining a spec of type [('main, unit -> unit) t] with a main function of type ['main]; see the [basic] function below. Combinators in this library incrementally build up the type of main according to what command-line parameters it expects, so the resulting type of [main] is something like: [arg1 -> ... -> argN -> unit -> unit] It may help to think of [('a, 'b) t] as a function space ['a -> 'b] embellished with information about: {ul {- how to parse command line} {- what the command does and how to call it} {- how to auto-complete a partial command line}} One can view a value of type [('main_in, 'main_out) t] as function that transforms a main function from type ['main_in] to ['main_out], typically by supplying some arguments. E.g. a value of type [Spec.t] might have type: {[ (arg1 -> ... -> argN -> 'r, 'r) Spec.t ]} Such a value can transform a main function of type [arg1 -> ... -> argN -> 'r] by supplying it argument values of type [arg1], ..., [argn], leaving a main function whose type is ['r]. In the end, [Command.basic] takes a completed spec where ['r = unit -> unit], and hence whose type looks like: {[ (arg1 -> ... -> argN -> unit -> unit, unit -> unit) Spec.t ]} A value of this type can fully apply a main function of type [arg1 -> ... -> argN -> unit -> unit] to all its arguments. The final unit argument allows the implementation to distinguish between the phases of (1) parsing the command line and (2) running the body of the command. Exceptions raised in phase (1) lead to a help message being displayed alongside the exception. Exceptions raised in phase (2) are displayed without any command line help. The view of [('main_in, main_out) Spec.t] as a function from ['main_in] to ['main_out] is directly reflected by the [step] function, whose type is: {[ val step : ('m1 -> 'm2) -> ('m1, 'm2) t ]} *) (** [spec1 ++ spec2 ++ ... ++ specN] composes spec1 through specN. For example, if [spec_a] and [spec_b] have types: {[ spec_a: (a1 -> ... -> aN -> 'ra, 'ra) Spec.t spec_b: (b1 -> ... -> bM -> 'rb, 'rb) Spec.t ]} then [spec_a ++ spec_b] has the following type: {[ (a1 -> ... -> aN -> b1 -> ... -> bM -> 'rb, 'rb) Spec.t ]} So, [spec_a ++ spec_b] transforms a main function it by first supplying [spec_a]'s arguments of type [a1], ..., [aN], and then supplying [spec_b]'s arguments of type [b1], ..., [bm]. One can understand [++] as function composition by thinking of the type of specs as concrete function types, representing the transformation of a main function: {[ spec_a: \/ra. (a1 -> ... -> aN -> 'ra) -> 'ra spec_b: \/rb. (b1 -> ... -> bM -> 'rb) -> 'rb ]} Under this interpretation, the composition of [spec_a] and [spec_b] has type: {[ spec_a ++ spec_b : \/rc. (a1 -> ... -> aN -> b1 -> ... -> bM -> 'rc) -> 'rc ]} And the implementation is just function composition: {[ sa ++ sb = fun main -> sb (sa main) ]} *) (** the empty command-line spec *) val empty : ('m, 'm) t (** command-line spec composition *) val (++) : ('m1, 'm2) t -> ('m2, 'm3) t -> ('m1, 'm3) t (** add a rightmost parameter onto the type of main *) val (+>) : ('m1, 'a -> 'm2) t -> 'a param -> ('m1, 'm2) t (** add a leftmost parameter onto the type of main *) val (+<) : ('m1, 'm2) t -> 'a param -> ('a -> 'm1, 'm2) t (** this function should only be used as a workaround in situations where the order of composition is at odds with the order of anonymous arguments due to factoring out some common spec *) (** combinator for patching up how parameters are obtained or presented *) val step : ('m1 -> 'm2) -> ('m1, 'm2) t (** Here are a couple examples of some of its many uses {ul {li {i introducing labeled arguments} {v step (fun m v -> m ~foo:v) +> flag "-foo" no_arg : (foo:bool -> 'm, 'm) t v}} {li {i prompting for missing values} {v step (fun m user -> match user with | Some user -> m user | None -> print_string "enter username: "; m (read_line ())) +> flag "-user" (optional string) ~doc:"USER to frobnicate" : (string -> 'm, 'm) t v}} } A use of [step] might look something like: {[ step (fun main -> let ... in main x1 ... xN) : (arg1 -> ... -> argN -> 'r, 'r) t ]} Thus, [step] allows one to write arbitrary code to decide how to transform a main function. As a simple example: {[ step (fun main -> main 13.) : (float -> 'r, 'r) t ]} This spec is identical to [const 13.]; it transforms a main function by supplying it with a single float argument, [13.]. As another example: {[ step (fun m v -> m ~foo:v) : (foo:'foo -> 'r, 'foo -> 'r) t ]} This spec transforms a main function that requires a labeled argument into a main function that requires the argument unlabeled, making it easily composable with other spec combinators. *) (** combinator for defining a class of commands with common behavior *) val wrap : (run:('m1 -> 'r1) -> main:'m2 -> 'r2) -> ('m1, 'r1) t -> ('m2, 'r2) t (** Here are two examples of command classes defined using [wrap] {ul {li {i print top-level exceptions to stderr} {v wrap (fun ~run ~main -> Exn.handle_uncaught ~exit:true (fun () -> run main) ) : ('m, unit) t -> ('m, unit) t v}} {li {i iterate over lines from stdin} {v wrap (fun ~run ~main -> In_channel.iter_lines stdin ~f:(fun line -> run (main line)) ) : ('m, unit) t -> (string -> 'm, unit) t v}} } *) val of_params : ('a, 'b) Param.Args.t -> ('a, 'b) t module Arg_type : module type of Arg_type with type 'a t = 'a Arg_type.t include module type of Arg_type.Export type 'a flag = 'a Flag.t (** a flag specification *) include module type of Flag with type 'a t := 'a flag (** [map_flag flag ~f] transforms the parsed result of [flag] by applying [f] *) val map_flag : 'a flag -> f:('a -> 'b) -> 'b flag (** [flags_of_args_exn args] creates a spec from [Caml.Arg.t]s, for compatibility with ocaml's base libraries. Fails if it encounters an arg that cannot be converted. NOTE: There is a difference in side effect ordering between [Caml.Arg] and [Command]. In the [Arg] module, flag handling functions embedded in [Caml.Arg.t] values will be run in the order that flags are passed on the command line. In the [Command] module, using [flags_of_args_exn flags], they are evaluated in the order that the [Caml.Arg.t] values appear in [flags]. *) val flags_of_args_exn : Core_kernel.Std.Arg.t list -> ('a, 'a) t type 'a anons = 'a Anons.t (** a specification of some number of anonymous arguments *) include module type of Anons with type 'a t := 'a anons (** [map_anons anons ~f] transforms the parsed result of [anons] by applying [f] *) val map_anons : 'a anons -> f:('a -> 'b) -> 'b anons end type t (** commands which can be combined into a hierarchy of subcommands *) type ('main, 'result) basic_command = summary : string -> ?readme : (unit -> string) -> ('main, unit -> 'result) Spec.t -> 'main -> t (** [basic ~summary ?readme spec main] is a basic command that executes a function [main] which is passed parameters parsed from the command line according to [spec]. [summary] is to contain a short one-line description of its behavior. [readme] is to contain any longer description of its behavior that will go on that commands' help screen. *) val basic : ('main, unit) basic_command type ('main, 'result) basic_command' = summary : string -> ?readme : (unit -> string) -> ('main, unit -> 'result) Param.Args.t -> 'main -> t (** Same general behavior as [basic], but takes a command line specification built up using [Params] instead of [Spec]. *) val basic' : ('main, unit) basic_command' (** [group ~summary subcommand_alist] is a compound command with named subcommands, as found in [subcommand_alist]. [summary] is to contain a short one-line description of the command group. [readme] is to contain any longer description of its behavior that will go on that command's help screen. NOTE: subcommand names containing underscores will be rejected. Use dashes instead. [body] is called when no additional arguments are passed -- in particular, when no subcommand is passed. Its [path] argument is the subcommand path by which the group command was reached. *) val group : summary : string -> ?readme : (unit -> string) -> ?preserve_subcommand_order : unit -> ?body : (path:string list -> unit) -> (string * t) list -> t (** [exec ~summary ~path_to_exe] runs [exec] on the executable at [path_to_exe]. If [path_to_exe] is [`Absolute path] then [path] is executed without any further qualification. If it is [`Relative_to_me path] then [Filename.dirname Sys.executable_name ^ "/" ^ path] is executed instead. All of the usual caveats about [Sys.executable_name] apply: specifically, it may only return an absolute path in Linux. On other operating systems it will return [Sys.argv.(0)]. Care has been taken to support nesting multiple executables built with Command. In particular, recursive help and autocompletion should work as expected. NOTE: non-Command executables can be used with this function but will still be executed when [help -recursive] is called or autocompletion is attempted (despite the fact that neither will be particularly helpful in this case). This means that if you have a shell script called "reboot-everything.sh" that takes no arguments and reboots everything no matter how it is called, you shouldn't use it with [exec]. Additionally, no loop detection is attempted, so if you nest an executable within itself, [help -recursive] and autocompletion will hang forever (although actually running the subcommand will work). *) val exec : summary : string -> ?readme : (unit -> string) -> path_to_exe : [ `Absolute of string | `Relative_to_me of string ] -> unit -> t (** extract the summary string for a command *) val summary : t -> string module Shape : sig type command type t = | Basic | Group of (string * command) list | Exec of (unit -> t) end with type command := t (** expose the shape of a command *) val shape : t -> Shape.t (** Run a command against [Sys.argv], or [argv] if it is specified. [extend] can be used to add extra command line arguments to basic subcommands of the command. [extend] will be passed the (fully expanded) path to a command, and its output will be appended to the list of arguments being processed. For example, suppose a program like this is compiled into [exe]: {[ let bar = Command.basic ... let foo = Command.group ~summary:... ["bar", bar] let main = Command.group ~summary:... ["foo", foo] Command.run ~extend:(fun _ -> ["-baz"]) main ]} Then if a user ran [exe f b], [extend] would be passed [["foo"; "bar"]] and ["-baz"] would be appended to the command line for processing by [bar]. This can be used to add a default flags section to a user config file. *) val run : ?version : string -> ?build_info : string -> ?argv : string list -> ?extend : (string list -> string list) -> t -> unit (** [Deprecated] should be used only by [Core_extended.Deprecated_command]. At some point it will go away. *) module Deprecated : sig module Spec : sig val no_arg : hook:(unit -> unit) -> bool Spec.flag val escape : hook:(string list -> unit) -> string list option Spec.flag val ad_hoc : usage_arg:string -> string list Spec.anons end val summary : t -> string val help_recursive : cmd : string -> with_flags : bool -> expand_dots : bool -> t -> string -> (string * string) list val run : t -> cmd : string -> args : string list -> is_help : bool -> is_help_rec : bool -> is_help_rec_flags : bool -> is_expand_dots : bool -> unit val get_flag_names : t -> string list val version : string val build_info : string end core-113.00.00/src/commutative_group.ml000066400000000000000000000000461256461075500176510ustar00rootroot00000000000000include Core_kernel.Commutative_group core-113.00.00/src/comparable.ml000066400000000000000000000000371256461075500162050ustar00rootroot00000000000000include Core_kernel.Comparable core-113.00.00/src/comparable_intf.ml000066400000000000000000000000441256461075500172230ustar00rootroot00000000000000include Core_kernel.Comparable_intf core-113.00.00/src/comparator.ml000066400000000000000000000000371256461075500162470ustar00rootroot00000000000000include Core_kernel.Comparator core-113.00.00/src/constrained_float.ml000066400000000000000000000000461256461075500175760ustar00rootroot00000000000000include Core_kernel.Constrained_float core-113.00.00/src/container.ml000066400000000000000000000000361256461075500160610ustar00rootroot00000000000000include Core_kernel.Container core-113.00.00/src/core.mldylib000066400000000000000000000001311256461075500160470ustar00rootroot00000000000000# OASIS_START # DO NOT EDIT (digest: 83168e6cb289d732cc78427b51f93153) Core # OASIS_STOP core-113.00.00/src/core.mllib000066400000000000000000000001311256461075500155120ustar00rootroot00000000000000# OASIS_START # DO NOT EDIT (digest: 83168e6cb289d732cc78427b51f93153) Core # OASIS_STOP core-113.00.00/src/core.mlpack000066400000000000000000000042271256461075500156740ustar00rootroot00000000000000# OASIS_START # DO NOT EDIT (digest: 565d4213064a6d7189e2c5fb9e9457a3) Bigbuffer Bigstring_marshal Bigstring Caml Check_std Command Core_condition Core_filename Core_list Core_mutex Core_sys Core_thread Core_unix Crc Daemon Date0 Date Debug Interval_intf Interval Iobuf_debug Iobuf_intf Iobuf Iobuf_tests Limiter Limiter_unit_tests Linux_ext Lock_file Mutex0 Nano_mutex Ofday Piecewise_linear_intf Piecewise_linear Process_env Signal Span Squeue Stable Std Syscall_result_intf Syscall_result Syslog Thread_safe_queue_unit_tests Time0 Time_internal Time Time_ns_benchmarks Time_ns Time_stamp_counter Time_stamp_counter_benchmarks Timing_wheel_float Timing_wheel_float_unit_tests Unix_error User_and_group Uuid Weak_hashtbl Zone Array_permute Avltree Bag Bigbuffer_internal Bigsubstring Binable Binable0 Binary_packing Blang Bool Bounded_int_table Bucket Byte_units Commutative_group Comparable Comparable_intf Comparator Constrained_float Container Core_arg Core_array Core_bin_prot Core_char Core_field Core_hashtbl Core_hashtbl_intf Core_int Core_int32 Core_int63 Core_int64 Core_lazy Core_map Core_map_intf Core_map_unit_tests Core_nativeint Core_printexc Core_printf Core_random Core_set Core_set_intf Core_set_unit_tests Core_sexp Core_stack Core_string Day_of_week Dequeue Doubly_linked Equal Error Exn Flags Flags_intf Float Float_intf Float_robust_compare Floatable Fn Force_once Fqueue Hash_heap Hash_queue Hash_set Hash_set_intf Hashable Heap Heap_block Host_and_port Identifiable In_channel Info Int_conversions Int_intf Int_replace_polymorphic_compare Int_set Intable Interfaces Invariant Make_substring Memo Monad Month Never_returns No_polymorphic_compare Nothing Nothing0 Only_in_test Option Or_error Ordered_collection_common Ordering Out_channel Pid Polymorphic_compare Polymorphic_compare_intf Pretty_printer Ref Result Robustly_comparable Set_once Sexpable Source_code_position Source_code_position0 Stable_containers Stable_internal Stable_unit_test Stable_unit_test_intf Staged Std_common Std_internal Std_kernel String_id Stringable Substring Substring_intf T Tuple Type_equal Union_find Unique_id Unique_id_intf Unit Univ Univ_map Unpack_buffer Validate Word_size # OASIS_STOP core-113.00.00/src/core_arg.ml000066400000000000000000000000351256461075500156570ustar00rootroot00000000000000include Core_kernel.Core_arg core-113.00.00/src/core_array.ml000066400000000000000000000000371256461075500162260ustar00rootroot00000000000000include Core_kernel.Core_array core-113.00.00/src/core_bin_prot.ml000066400000000000000000000000421256461075500167200ustar00rootroot00000000000000include Core_kernel.Core_bin_prot core-113.00.00/src/core_char.ml000066400000000000000000000000361256461075500160240ustar00rootroot00000000000000include Core_kernel.Core_char core-113.00.00/src/core_condition.ml000066400000000000000000000004161256461075500170770ustar00rootroot00000000000000include Condition let phys_equal = Caml.(==) let equal (t : t) t' = phys_equal t t' external condition_timedwait : Condition.t -> Mutex.t -> float -> bool = "unix_condition_timedwait" let timedwait cnd mtx time = condition_timedwait cnd mtx (Time.to_float time) core-113.00.00/src/core_condition.mli000066400000000000000000000012661256461075500172540ustar00rootroot00000000000000open Core_kernel.Std type t = Condition.t val create : unit -> t val equal : t -> t -> bool val wait : t -> Mutex.t -> unit (** [timedwait cond mtx timeout] waits on condition variable [cond] with mutex [mtx] until either the condition is signalled, or until [timeout] expires. Note that [timeout] is an absolute Unix-time to prevent time-related race conditions. @return [false] iff the timer expired, but this does not mean that the condition is not true due to an unavoidable race condition in the system call. See [man pthread_cond_timedwait] for details. *) val timedwait : t -> Mutex.t -> Time.t -> bool val signal : t -> unit val broadcast : t -> unit core-113.00.00/src/core_field.ml000066400000000000000000000000371256461075500161730ustar00rootroot00000000000000include Core_kernel.Core_field core-113.00.00/src/core_filename.ml000066400000000000000000000155261256461075500167010ustar00rootroot00000000000000open Core_kernel.Std open Printf include struct open Caml.Filename let check_suffix = check_suffix let chop_extension = chop_extension let chop_suffix = chop_suffix let current_dir_name = current_dir_name let is_implicit = is_implicit let is_relative = is_relative let parent_dir_name = parent_dir_name let dir_sep = dir_sep let quote = quote let temp_dir_name = temp_dir_name end let is_absolute p = not (is_relative p) (* Pathname resolution *) external realpath : string -> string = "unix_realpath" let concat p1 p2 = if p1 = "" then failwithf "Filename.concat called with an empty string as its first \ argument (second argument: %s)" p2 (); let rec collapse_trailing s = match String.rsplit2 s ~on:'/' with | Some ("", ("." | "")) -> "" | Some (s , ("." | "")) -> collapse_trailing s | None | Some _ -> s in let rec collapse_leading s = match String.lsplit2 s ~on:'/' with | Some (("." | ""), s) -> collapse_leading s | Some _ | None -> s in collapse_trailing p1 ^ "/" ^ collapse_leading p2 let (^/) = Filename.concat (* Finds the largest index i in [s] that is less than [from] and for which [f s.[i]] returns true. Then it returns [i+1]. Raises an exception if [from] isn't a valid index in [s]. *) let string_rexists s ~f ~from:n = let rec loop n = if n = 0 then None else if f s.[n - 1] then Some n else loop (n - 1) in loop n let skip_end_slashes s ~from = match string_rexists s ~from ~f:(fun c -> c <> '/') with | Some v -> `Ends_at v | None -> `All_slashes (* Fix for #0004549. (in the inria bug tracker) *) let split = function | "" -> ".", "." | s -> match skip_end_slashes s ~from:(String.length s) with | `All_slashes -> "/", "/" | `Ends_at basename_end -> match string_rexists s ~f:(fun c -> c = '/') ~from:basename_end with | None -> ".", String.sub ~pos:0 ~len:basename_end s | Some basename_start -> let basename = String.sub s ~pos:basename_start ~len:(basename_end - basename_start) in let dirname = match skip_end_slashes s ~from:basename_start with | `All_slashes -> "/" | `Ends_at dirname_end -> String.sub ~pos:0 ~len:dirname_end s in dirname, basename (* http://www.opengroup.org/onlinepubs/9699919799/utilities/basename.html http://www.opengroup.org/onlinepubs/9699919799/utilities/dirname.html *) let basename path = snd (split path) let dirname path = fst (split path) (* [max_pathname_component_size] comes from getconf _POSIX_NAME_MAX / *) let max_pathname_component_size = 255 let is_posix_pathname_component s = let module S = String in s <> "." && s <> ".." && 0 < S.length s && S.length s <= max_pathname_component_size && not (S.contains s '/') && not (S.contains s '\000') let prng = Random.State.make_self_init () (* try up to 1000 times to not get a Sys_error when opening a temp file / name: *) let retry ?(in_dir=temp_dir_name) ~f prefix suffix = let escape s = String.map s ~f:(function | '/' | '\'' | '\000' | '\n' | '-' -> '_' | c -> c) in let prefix = escape prefix in let suffix = escape suffix in let rec try_name counter = let name = let rnd = Random.State.bits prng land 0xFF_FFFF in (Printf.sprintf "%s%06x%s" prefix rnd suffix) in let name = concat in_dir name in try f name with Sys_error _ | Unix.Unix_error _ as e -> if counter >= 1000 then raise e else try_name (counter + 1) in try_name 0 let open_temp_mode = [Open_wronly; Open_creat; Open_excl] (* these functions are the same as the ones in the std lib but you can override the temporary directory you are working in. They also try the exact filename specified by the user before reverting to the "try with" machinery. *) let temp_dir ?(perm=0o700) ?in_dir prefix suffix = retry ?in_dir prefix suffix ~f:(fun name -> Unix.mkdir name perm; name) let open_temp_file ?(perm=0o600) ?in_dir prefix suffix = retry ?in_dir prefix suffix ~f:(fun name -> (name, open_out_gen open_temp_mode perm name)) let temp_file ?perm ?in_dir prefix suffix = let (name, oc) = open_temp_file ?perm ?in_dir prefix suffix in Out_channel.close oc; name let root = "/" let split_extension fn = let dir, fn = match String.rsplit2 ~on:'/' fn with | None -> (None, fn) | Some (path, fn) -> (Some path, fn) in let fn, ext = match String.rsplit2 ~on:'.' fn with | None -> (fn, None) | Some (base_fn, ext) -> (base_fn, Some ext) in let fn = match dir with | None -> fn | Some dir -> dir ^ "/" ^ fn in (fn, ext) TEST = split_extension "/foo/my_file" = ("/foo/my_file", None) TEST = split_extension "/foo/my_file.txt" = ("/foo/my_file", Some "txt") TEST = split_extension "/foo/my_file.1.txt" = ("/foo/my_file.1", Some "txt") TEST = split_extension "/home/c.falls/my_file" = ("/home/c.falls/my_file", None) TEST = split_extension "/home/c.falls/my_file.txt" = ("/home/c.falls/my_file", Some "txt") TEST = split_extension "/home/c.falls/my_file.1.txt" = ("/home/c.falls/my_file.1", Some "txt") TEST = split_extension "my_file" = ("my_file", None) TEST = split_extension "my_file.txt" = ("my_file", Some "txt") TEST = split_extension "my_file.1.txt" = ("my_file.1", Some "txt") TEST = split_extension "/my_file" = ("/my_file", None) TEST = split_extension "/my_file.txt" = ("/my_file", Some "txt") TEST = split_extension "/my_file.1.txt" = ("/my_file.1", Some "txt") let parts filename = let rec loop acc filename = match split filename with | "." as base, "." -> base :: acc | "/" as base, "/" -> base :: acc | rest, dir -> loop (dir :: acc) rest in loop [] filename let of_parts = function | [] -> failwith "Filename.of_parts: empty parts list" | root :: rest -> List.fold rest ~init:root ~f:(fun acc part -> acc ^/ part) TEST_UNIT = List.iter ~f:(fun (path, pieces) -> <:test_result< string >> ~expect:path (of_parts pieces); <:test_result< string list >> ~expect:pieces (parts path)) [ "/tmp/foo/bar/baz", ["/"; "tmp"; "foo"; "bar"; "baz"] ; ".", ["."] ; "/", ["/"] ; "./foo", ["."; "foo"] ] TEST = parts "/tmp/foo/bar/baz/" = ["/"; "tmp"; "foo"; "bar"; "baz"] TEST = parts "//tmp//foo//bar" = ["/"; "tmp"; "foo"; "bar"] TEST = parts "" = ["."] TEST = parts "./" = ["."] TEST = parts "./." = ["."] TEST = parts "././." = ["."; "."] TEST = parts "foo" = ["."; "foo"] TEST = parts "./foo/" = ["."; "foo"] TEST = parts "./foo/." = ["."; "foo"; "."] TEST = of_parts ["."; "."; "."] = "././." core-113.00.00/src/core_filename.mli000066400000000000000000000140171256461075500170440ustar00rootroot00000000000000(** Warning! this library assumes we are in a POSIX compliant OS. *) open Core_kernel.Std (** The path of the root.*) val root : string (** {2 Pathname resolution} *) (** [realpath path] @return the canonicalized absolute pathname of [path]. @raise Unix_error on errors. *) val realpath : string -> string (** [is_posix_pathname_component f] @return true if [f] is a valid filename in a POSIX compliant OS (a path component and not a full path). http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_169 *) val is_posix_pathname_component : string -> bool (** [temp_file ?perm ?in_dir_name prefix suffix] Returns the name of a fresh temporary file in the temporary directory. The base name of the temporary file is formed by concatenating prefix, then a 6-digit hex number, then suffix. The temporary file is created empty. The file is guaranteed to be fresh, i.e. not already existing in the directory. @param in_dir the directory in which to create the temporary file. The default is [temp_dir_name] @param perm the permission of the temporary file. The default value is [0o600] (readable and writable only by the file owner) Note that prefix and suffix will be changed when necessary to make the final filename valid POSIX. [temp_dir] is the same as [temp_file] but creates a temporary directory. *) val temp_file: ?perm:int -> ?in_dir: string -> string -> string -> string val temp_dir : ?perm:int -> ?in_dir: string -> string -> string -> string (** The name of the temporary directory: Under Unix, the value of the [TMPDIR] environment variable, or "/tmp" if the variable is not set. Under Windows, the value of the [TEMP] environment variable, or "." if the variable is not set. *) val temp_dir_name : string (** Same as {!Core_filename.temp_file}, but returns both the name of a fresh temporary file, and an output channel opened (atomically) on this file. This function is more secure than [temp_file]: there is no risk that the temporary file will be modified (e.g. replaced by a symbolic link) before the program opens it. *) val open_temp_file : ?perm: int -> ?in_dir: string -> string -> string -> string * out_channel (** The conventional name for the current directory (e.g. [.] in Unix). *) val current_dir_name : string (** The conventional name for the parent of the current directory (e.g. [..] in Unix). *) val parent_dir_name : string (** The directory separator (e.g. [/] in Unix). *) val dir_sep : string (** [concat p1 p2] returns a path equivalent to [p1 ^ "/" ^ p2]. In the resulting path p1 (resp. p2) has all its trailing (resp. leading) "." and "/" removed. eg: concat "a/." ".//b" => "a/b" concat "." "b" => "./b" concat "a" "." => "a/." concat "a" "/b" => "a/b" @throws Failure if [p1] is empty. *) val concat : string -> string -> string (** Return [true] if the file name is relative to the current directory, [false] if it is absolute (i.e. in Unix, starts with [/]). *) val is_relative : string -> bool val is_absolute : string -> bool (** Return [true] if the file name is relative and does not start with an explicit reference to the current directory ([./] or [../] in Unix), [false] if it starts with an explicit reference to the root directory or the current directory. *) val is_implicit : string -> bool (** [check_suffix name suff] returns [true] if the filename [name] ends with the suffix [suff]. *) val check_suffix : string -> string -> bool (** [chop_suffix name suff] removes the suffix [suff] from the filename [name]. The behavior is undefined if [name] does not end with the suffix [suff]. *) val chop_suffix : string -> string -> string (** Return the given file name without its extension. The extension is the shortest suffix starting with a period and not including a directory separator, [.xyz] for instance. Raise [Invalid_argument] if the given name does not contain an extension. *) val chop_extension : string -> string (** [split_extension fn] return the portion of the filename before the extension and the (optional) extension. Example: split_extension "/foo/my_file" = ("/foo/my_file", None) split_extension "/foo/my_file.txt" = ("/foo/my_file", Some "txt") split_extension "/home/c.falls/my_file" = ("/home/c.falls/my_file", None) *) val split_extension : string -> (string * string option) (** Respects the posix semantic. Split a file name into directory name / base file name. [concat (dirname name) (basename name)] returns a file name which is equivalent to [name]. Moreover, after setting the current directory to [dirname name] (with {!Sys.chdir}), references to [basename name] (which is a relative file name) designate the same file as [name] before the call to {!Sys.chdir}. The result is not specified if the argument is not a valid file name (for example, under Unix if there is a NUL character in the string). *) val basename : string -> string (** See {!Filename.basename}. *) val dirname : string -> string (** [split filename] returns (dirname filename, basename filename) *) val split : string -> string * string (** [parts filename] returns a list of path components in order. For instance: /tmp/foo/bar/baz -> ["/"; "tmp"; "foo"; "bar"; "baz"]. The first component is always either "." for relative paths or "/" for absolute ones. *) val parts : string -> string list (** [of_parts parts] joins a list of path components into a path. It does roughly the opposite of [parts], but they fail to be precisely mutually inverse because of ambiguities like multiple consecutive slashes and . components. Raises an error if given an empty list. *) val of_parts : string list -> string (** Return a quoted version of a file name, suitable for use as one argument in a command line, escaping all meta-characters. Warning: under Windows, the output is only suitable for use with programs that follow the standard Windows quoting conventions. *) val quote : string -> string core-113.00.00/src/core_hashtbl.ml000066400000000000000000000000411256461075500165300ustar00rootroot00000000000000include Core_kernel.Core_hashtbl core-113.00.00/src/core_hashtbl_intf.ml000066400000000000000000000000461256461075500175550ustar00rootroot00000000000000include Core_kernel.Core_hashtbl_intf core-113.00.00/src/core_int.ml000066400000000000000000000000351256461075500157000ustar00rootroot00000000000000include Core_kernel.Core_int core-113.00.00/src/core_int32.ml000066400000000000000000000000371256461075500160470ustar00rootroot00000000000000include Core_kernel.Core_int32 core-113.00.00/src/core_int63.ml000066400000000000000000000000371256461075500160530ustar00rootroot00000000000000include Core_kernel.Core_int63 core-113.00.00/src/core_int64.ml000066400000000000000000000000371256461075500160540ustar00rootroot00000000000000include Core_kernel.Core_int64 core-113.00.00/src/core_lazy.ml000066400000000000000000000000361256461075500160660ustar00rootroot00000000000000include Core_kernel.Core_lazy core-113.00.00/src/core_list.ml000066400000000000000000000001161256461075500160610ustar00rootroot00000000000000include Core_kernel.Core_list let to_sequence = Core_kernel.Sequence.of_list core-113.00.00/src/core_map.ml000066400000000000000000000000351256461075500156630ustar00rootroot00000000000000include Core_kernel.Core_map core-113.00.00/src/core_map_intf.ml000066400000000000000000000000421256461075500167010ustar00rootroot00000000000000include Core_kernel.Core_map_intf core-113.00.00/src/core_map_unit_tests.ml000066400000000000000000000000501256461075500201410ustar00rootroot00000000000000include Core_kernel.Core_map_unit_tests core-113.00.00/src/core_mutex.ml000066400000000000000000000006001256461075500162460ustar00rootroot00000000000000INCLUDE "core_config.mlh" IFDEF MUTEX_TIMED_LOCK THEN open Core_kernel.Std include Mutex0 (* POSIX thread functions *) external mutex_timedlock : Mutex.t -> float -> bool = "unix_mutex_timedlock" let timedlock mtx time = mutex_timedlock mtx (Time.to_float time) let timedlock = Ok timedlock ELSE include Mutex0 let timedlock = Or_error.unimplemented "Mutex.timedlock" ENDIF core-113.00.00/src/core_mutex.mli000066400000000000000000000040041256461075500164210ustar00rootroot00000000000000open Core_kernel.Std type t = Mutex.t val create : unit -> t val equal : t -> t -> bool (** [lock mtx] locks [mtx], possibly waiting for it to be released first by another thread. @raise Unix_error if [lock] attempts to acquire [mtx] recursively. *) val lock : t -> unit (** [try_lock] is like [lock], but always returns immediately. If the calling thread or another one already has the mutex it returns [`Already_held_by_me_or_other], otherwise it locks it and returns [`Acquired]. *) val try_lock : t -> [ `Already_held_by_me_or_other | `Acquired ] (** [timedlock mtx timeout] like [lock], but takes a [timeout] parameter. @return [true] if the mutex was acquired, or [false] when [timeout] expires otherwise. @raise Unix_error if [timedlock] attempts to acquire [mtx] recursively. *) val timedlock : (t -> Time.t -> bool) Or_error.t (** [unlock mtx] unlocks [mtx]. @raise Unix_error if [unlock] attempts to release an unacquired mutex or a mutex held by another thread. *) val unlock : t -> unit (* [critical_section t ~f] locks [t], runs [f], unlocks [t], and returns the result of [f] (or raises if [f] raised). *) val critical_section : t -> f:(unit -> 'a) -> 'a (** [synchronize f] creates a mutex and returns a new function that is identical to [f] except that the mutex is held during its execution. *) val synchronize : ('a -> 'b) -> ('a -> 'b) (** [update_signal mtx cnd ~f] updates some state within a critical section protected by mutex [mtx] using function [f] and signals condition variable [cnd] after finishing. If [f] raises an exception, the condition will NOT be signaled! *) val update_signal : t -> Condition.t -> f:(unit -> 'a) -> 'a (** [update_broadcast mtx cnd ~f] updates some state within a critical section protected by mutex [mtx] using function [f] and broadcasts condition variable [cnd] after finishing. If [f] raises an exception, the condition will NOT be broadcast! *) val update_broadcast : t -> Condition.t -> f:(unit -> 'a) -> 'a core-113.00.00/src/core_nativeint.ml000066400000000000000000000000431256461075500171060ustar00rootroot00000000000000include Core_kernel.Core_nativeint core-113.00.00/src/core_printexc.ml000066400000000000000000000000421256461075500167400ustar00rootroot00000000000000include Core_kernel.Core_printexc core-113.00.00/src/core_printf.ml000066400000000000000000000000401256461075500164040ustar00rootroot00000000000000include Core_kernel.Core_printf core-113.00.00/src/core_random.ml000066400000000000000000000000401256461075500163620ustar00rootroot00000000000000include Core_kernel.Core_random core-113.00.00/src/core_set.ml000066400000000000000000000000351256461075500157010ustar00rootroot00000000000000include Core_kernel.Core_set core-113.00.00/src/core_set_intf.ml000066400000000000000000000000421256461075500167170ustar00rootroot00000000000000include Core_kernel.Core_set_intf core-113.00.00/src/core_set_unit_tests.ml000066400000000000000000000000501256461075500201570ustar00rootroot00000000000000include Core_kernel.Core_set_unit_tests core-113.00.00/src/core_sexp.ml000066400000000000000000000000361256461075500160660ustar00rootroot00000000000000include Core_kernel.Core_sexp core-113.00.00/src/core_stack.ml000066400000000000000000000000371256461075500162150ustar00rootroot00000000000000include Core_kernel.Core_stack core-113.00.00/src/core_string.ml000066400000000000000000000000401256461075500164100ustar00rootroot00000000000000include Core_kernel.Core_string core-113.00.00/src/core_sys.ml000066400000000000000000000053731256461075500157360ustar00rootroot00000000000000open Core_kernel.Std module LargeFile = Unix.LargeFile let getenv var = try Some (Sys.getenv var) with Not_found -> None let getenv_exn var = match getenv var with | Some x -> x | None -> Printf.failwithf "Sys.getenv_exn: environment variable %s is not set" var () let stat_check_exn f ?(follow_symlinks = true) path = let rec loop () = try f (if follow_symlinks then LargeFile.stat path else LargeFile.lstat path) with | Unix.Unix_error(Unix.EINTR,_,_) -> loop () | Unix.Unix_error ((Unix.ENOENT|Unix.ENOTDIR), _, _) -> false in loop () ;; let stat_check f ?follow_symlinks path = try if stat_check_exn f ?follow_symlinks path then `Yes else `No with | Unix.Unix_error ((Unix.EACCES|Unix.ELOOP), _, _) -> `Unknown ;; let file_exists = stat_check (fun _ -> true) let file_exists_exn = stat_check_exn (fun _ -> true) let is_directory = stat_check (fun stat -> stat.LargeFile.st_kind = Unix.S_DIR) let is_directory_exn = stat_check_exn (fun stat -> stat.LargeFile.st_kind = Unix.S_DIR) let is_file = stat_check (fun stat -> stat.LargeFile.st_kind = Unix.S_REG) let is_file_exn = stat_check_exn (fun stat -> stat.LargeFile.st_kind = Unix.S_REG) include struct open Caml.Sys let argv = argv let executable_name = executable_name let remove = remove let rename = rename let command = command let chdir = chdir let getcwd = getcwd let readdir = readdir let interactive = interactive let os_type = os_type let word_size = word_size let big_endian = big_endian exception Break = Break let catch_break = catch_break let ocaml_version = ocaml_version end exception Command_failed_with_status of Int.t * String.t with sexp let command_exn string = let status = command string in if status <> 0 then raise (Command_failed_with_status (status, string)) ;; let fold_dir ~init ~f directory = Array.fold (readdir directory) ~f ~init let ls_dir directory = Array.to_list (readdir directory) (* This function takes six units to cause ocaml to call a different function when executing bytecode: http://caml.inria.fr/pub/docs/manual-ocaml/manual033.html#19.1.2 *) external executing_bytecode : unit -> unit -> unit -> unit -> unit -> unit -> bool = "executing_bytecode" "not_executing_bytecode" "noalloc" let execution_mode () = if executing_bytecode () () () () () () then `Bytecode else `Native TEST = execution_mode () = (if String.is_suffix argv.(0) ~suffix:".exe" || String.is_suffix argv.(0) ~suffix:".native" then `Native else `Bytecode) (* returns size, in bits, of an [int] type in C *) external c_int_size : unit -> int = "c_int_size" "noalloc" TEST = let size = c_int_size () in size >= 16 && size <= Sys.word_size core-113.00.00/src/core_sys.mli000066400000000000000000000132361256461075500161040ustar00rootroot00000000000000(** System interface. *) open Core_kernel.Std (** The command line arguments given to the process. The first element is the command name used to invoke the program. The following elements are the command-line arguments given to the program. *) val argv : string array (** The name of the file containing the executable currently running. *) val executable_name : string (** For all of the following functions, [?follow_symlinks] defaults to [true]. *) (** [file_exists ~follow_symlinks path] Test whether the file in [path] exists on the file system. If [follow_symlinks] is [true] and [path] is a symlink the result concerns the target of the symlink. [`Unknown] is returned for files for which we cannot successfully determine whether they are on the system or not (e.g. files in directories to which we do not have read permission). *) val file_exists : ?follow_symlinks:bool (* defaults to true *) -> string -> [ `Yes | `No | `Unknown ] (** Same as [file_exists] but blows up on [`Unknown] *) val file_exists_exn : ?follow_symlinks:bool (* defaults to true *) -> string -> bool (** Returns [`Yes] if the file exists and is a directory*) val is_directory : ?follow_symlinks:bool (* defaults to true *) -> string -> [ `Yes | `No | `Unknown ] (** Returns [`Yes] if the file exists and is a regular file *) val is_file : ?follow_symlinks:bool (* defaults to true *) -> string -> [ `Yes | `No | `Unknown ] val is_directory_exn : ?follow_symlinks:bool (* defaults to true *) -> string -> bool val is_file_exn : ?follow_symlinks:bool (* defaults to true *) -> string -> bool (** Remove the given file name from the file system. *) val remove : string -> unit (** Rename a file. The first argument is the old name and the second is the new name. If there is already another file under the new name, [rename] may replace it, or raise an exception, depending on your operating system. *) val rename : string -> string -> unit (** Return the value associated to a variable in the process environment. Return [None] if the variable is unbound. *) val getenv : string -> string option val getenv_exn : string -> string (** Execute the given shell command and return its exit code. *) val command : string -> int (** [command_exn command] runs [command] and then raises an exception if it returns with nonzero exit status. *) val command_exn : string -> unit (** Change the current working directory of the process. *) val chdir : string -> unit (** Return the current working directory of the process. *) val getcwd : unit -> string (** Return the names of all files present in the given directory. Names denoting the current directory and the parent directory (["."] and [".."] in Unix) are not returned. Each string in the result is a file name rather than a complete path. There is no guarantee that the name strings in the resulting array will appear in any specific order; they are not, in particular, guaranteed to appear in alphabetical order. *) val readdir : string -> string array (* Call [readdir], and fold over the elements of the array. @raise Sys_error _ if readdir fails. As with [readdir], ["."] and [".."] are not returned raises the same exception than opendir and closedir. *) val fold_dir : init:'acc -> f:('acc -> string -> 'acc) -> string -> 'acc (** Same as [readdir], but return a list rather than an array. *) val ls_dir : string -> string list (** This reference is initially set to [false] in standalone programs and to [true] if the code is being executed under the interactive toplevel system [ocaml]. *) val interactive : bool ref (** Operating system currently executing the Caml program. One of - ["Unix"] (for all Unix versions, including Linux and Mac OS X), - ["Win32"] (for MS-Windows, OCaml compiled with MSVC++ or Mingw), - ["Cygwin"] (for MS-Windows, OCaml compiled with Cygwin). *) val os_type : string (** Size of one word on the machine currently executing the Caml program, in bits: 32 or 64. *) val word_size : int (** Whether the machine currently executing the Caml program is big-endian. *) val big_endian : bool (** Exception raised on interactive interrupt if {!Sys.catch_break} is on. *) exception Break (** Warning: this function clobbers the Signal.int (SIGINT) handler. SIGINT is the signal that's sent to your program when you hit CTRL-C. Warning: catch_break uses deep ocaml runtime magic to raise Sys.Break inside of the main execution context. Consider explicitly handling Signal.int instead. If all you want to do is terminate on CTRL-C you don't have to do any special setup, that's the default behavior. [catch_break] governs whether interactive interrupt (ctrl-C) terminates the program or raises the [Break] exception. Call [catch_break true] to enable raising [Break], and [catch_break false] to let the system terminate the program on user interrupt. *) val catch_break : bool -> unit (** [ocaml_version] is the version of Objective Caml. It is a string of the form ["major.minor[.patchlevel][+additional-info]"], where [major], [minor], and [patchlevel] are integers, and [additional-info] is an arbitrary string. The [[.patchlevel]] and [[+additional-info]] parts may be absent. *) val ocaml_version : string;; (** [execution_mode] tests whether the code being executed was compiled natively or to bytecode. *) val execution_mode : unit -> [ `Bytecode | `Native ] (** [c_int_size] returns the number of bits in a C [int]. Note that this can be different from [word_size]. For example, Linux x86-64 should have [word_size = 64], but [c_int_size () = 32] *) external c_int_size : unit -> int = "c_int_size" "noalloc" core-113.00.00/src/core_thread.ml000066400000000000000000000023561256461075500163650ustar00rootroot00000000000000open Core_kernel.Std let threads_have_been_created = ref false include Thread let create f arg = threads_have_been_created := true; let f arg = try f arg with x -> Printf.eprintf "%s\n%!" (Exn.to_string x); raise x in create f arg ;; let threads_have_been_created () = !threads_have_been_created let wait_signal sigs = wait_signal (List.map ~f:Signal.to_caml_int sigs) let sigmask cmd sigs = let cmd = match cmd with | `Set -> Unix.SIG_SETMASK | `Block -> Unix.SIG_BLOCK | `Unblock -> Unix.SIG_UNBLOCK in let sigs = List.map ~f:Signal.to_caml_int sigs in List.map ~f:Signal.of_caml_int (sigmask cmd sigs) ;; let num_threads () = let rec find_thread_count = function | [] -> None | line :: xs -> if String.is_prefix line ~prefix:"Threads:" then begin try Some (int_of_string (String.strip (snd (String.lsplit2_exn line ~on:':')))) with | _ -> None end else find_thread_count xs in try find_thread_count (In_channel.read_lines ("/proc/" ^ string_of_int (Unix.getpid ()) ^ "/status")) with _ -> None ;; let block_forever () = Event.sync (Event.receive (Event.new_channel ())) ;; core-113.00.00/src/core_thread.mli000066400000000000000000000111661256461075500165350ustar00rootroot00000000000000(** Lightweight threads. *) open Core_kernel.Std (** The type of thread handles. *) type t (** {6 Thread creation and termination} *) val create : ('a -> 'b) -> 'a -> t (** [Thread.create funct arg] creates a new thread of control, in which the function application [funct arg] is executed concurrently with the other threads of the program. The application of [Thread.create] returns the handle of the newly created thread. The new thread terminates when the application [funct arg] returns, either normally or by raising an uncaught exception. In the latter case, the exception is printed on standard error, but not propagated back to the parent thread. Similarly, the result of the application [funct arg] is discarded and not directly accessible to the parent thread. *) val self : unit -> t (** Return the thread currently executing. *) val id : t -> int (** Return the identifier of the given thread. A thread identifier is an integer that identifies uniquely the thread. It can be used to build data structures indexed by threads. *) val exit : unit -> unit (** Terminate prematurely the currently executing thread. *) (* This has been deliberately removed from the interface because it is an inherently unsafe operation and is never required *) (* val kill : t -> unit *) (** Terminate prematurely the thread whose handle is given. This functionality is available only with bytecode-level threads. *) (** {6 Suspending threads} *) val delay : float -> unit (** [delay d] suspends the execution of the calling thread for [d] seconds. The other program threads continue to run during this time. *) val join : t -> unit (** [join th] suspends the execution of the calling thread until the thread [th] has terminated. *) val wait_read : Unix.file_descr -> unit (** See {!Thread.wait_write}.*) val wait_write : Unix.file_descr -> unit (** Suspend the execution of the calling thread until at least one character is available for reading ({!Thread.wait_read}) or one character can be written without blocking ([wait_write]) on the given Unix file descriptor. *) val wait_timed_read : Unix.file_descr -> float -> bool (** See {!Thread.wait_timed_write}.*) val wait_timed_write : Unix.file_descr -> float -> bool (** Same as {!Thread.wait_read} and {!Thread.wait_write}, but wait for at most the amount of time given as second argument (in seconds). Return [true] if the file descriptor is ready for input/output and [false] if the timeout expired. *) val yield : unit -> unit (** Re-schedule the calling thread without suspending it. This function can be used to give scheduling hints, telling the scheduler that now is a good time to switch to other threads. *) (** {6 Management of signals} *) (** Signal handling follows the POSIX thread model: signals generated by a thread are delivered to that thread; signals generated externally are delivered to one of the threads that does not block it. Each thread possesses a set of blocked signals, which can be modified using {!Thread.sigmask}. This set is inherited at thread creation time. Per-thread signal masks are supported only by the system thread library under Unix, but not under Win32, nor by the VM thread library. *) val sigmask : Signal.sigprocmask_command -> Signal.t list -> Signal.t list (** [sigmask cmd sigs] changes the set of blocked signals for the calling thread. If [cmd] is [`Set], blocked signals are set to those in the list [sigs]. If [cmd] is [`Block], the signals in [sigs] are added to the set of blocked signals. If [cmd] is [`Unblock], the signals in [sigs] are removed from the set of blocked signals. [sigmask] returns the set of previously blocked signals for the thread. *) val wait_signal : Signal.t list -> int (** [wait_signal sigs] suspends the execution of the calling thread until the process receives one of the signals specified in the list [sigs]. It then returns the number of the signal received. Signal handlers attached to the signals in [sigs] will not be invoked. The signals [sigs] are expected to be blocked before calling [wait_signal]. *) (** Jane Street extensions *) (** [true] iff Thread.create has ever been called, even if there is currently only one running thread. *) val threads_have_been_created : unit -> bool (** [num_threads ()] attempts to return the number of currently running threads by parsing /proc. Since this is an operation frought with potential failure, we return an option in cases of failure *) val num_threads : unit -> int option (** [block_forever ()] will block the calling thread forever. *) val block_forever : unit -> 'a core-113.00.00/src/core_unix.ml000066400000000000000000002162411256461075500161010ustar00rootroot00000000000000(* Core_unix wraps the standard unix functions with an exception handler that inserts an informative string in the third field of Unix_error. The problem with the standard Unix_error that gets raised is that it doesn't include information about the arguments to the function that failed. *) INCLUDE "core_config.mlh" open Core_kernel.Std module Time_ns = Core_kernel.Time_ns_alternate_sexp module Unix = UnixLabels open Sexplib.Conv let ( ^/ ) = Core_filename.concat let failwithf = Printf.failwithf let atom x = Sexp.Atom x let list x = Sexp.List x let record l = list (List.map l ~f:(fun (name, value) -> list [atom name; value])) ;; (* No need to include a counter here. It just doesn't make sense to think we are going to be receiving a steady stream of interrupts. Glibc's macro doesn't have a counter either. *) let rec retry_until_no_eintr f = try f () with Unix.Unix_error (EINTR, _, _) -> retry_until_no_eintr f (* This wrapper improves the content of the Unix_error exception raised by the standard library (by including a sexp of the function arguments), and it optionally restarts syscalls on EINTR. *) let improve ?(restart = false) f make_arg_sexps = try if restart then retry_until_no_eintr f else f () with | Unix.Unix_error (e, s, _) -> let buf = Buffer.create 100 in let fmt = Format.formatter_of_buffer buf in Format.pp_set_margin fmt 10000; Sexp.pp_hum fmt (record (make_arg_sexps ())); Format.pp_print_flush fmt (); let arg_str = Buffer.contents buf in raise (Unix.Unix_error (e, s, arg_str)) ;; module File_descr = struct module M = struct type t = Unix.file_descr external to_int : t -> int = "%identity" external of_int : int -> t = "%identity" let of_string string = of_int (Int.of_string string) let to_string t = Int.to_string (to_int t) let sexp_of_t t = Int.sexp_of_t (to_int t) let t_of_sexp sexp = of_int (Int.t_of_sexp sexp) let hash t = Int.hash (to_int t) let compare t1 t2 = Int.compare (to_int t1) (to_int t2) end include M include (Hashable.Make (M)) include (Binable.Of_stringable (M)) let equal t1 t2 = to_int t1 = to_int t2 end let sprintf = Printf.sprintf external sync : unit -> unit = "unix_sync" external fsync : Unix.file_descr -> unit = "unix_fsync" external fdatasync : Unix.file_descr -> unit = "unix_fdatasync" external dirfd : Unix.dir_handle -> File_descr.t = "unix_dirfd" external readdir_ino : Unix.dir_handle -> string * nativeint = "unix_readdir_ino_stub" external unsetenv : string -> unit = "unix_unsetenv" external exit_immediately : int -> _ = "caml_sys_exit" external unsafe_read_assume_fd_is_nonblocking : File_descr.t -> string -> pos : int -> len : int -> int = "unix_read_assume_fd_is_nonblocking_stub" let check_string_args ~loc str ~pos ~len = if pos < 0 then invalid_arg (loc ^ ": pos < 0"); if len < 0 then invalid_arg (loc ^ ": len < 0"); let str_len = String.length str in if str_len < pos + len then invalid_arg (Printf.sprintf "Unix_ext.%s: length(str) < pos + len" loc) let get_opt_pos ~loc = function | Some pos -> if pos < 0 then invalid_arg (Printf.sprintf "Unix_ext.%s: pos < 0" loc); pos | None -> 0 let get_opt_len str ~pos = function | Some len -> len | None -> String.length str - pos let read_assume_fd_is_nonblocking fd ?pos ?len buf = let loc = "read_assume_fd_is_nonblocking" in let pos = get_opt_pos ~loc pos in let len = get_opt_len buf ~pos len in check_string_args ~loc buf ~pos ~len; unsafe_read_assume_fd_is_nonblocking fd buf ~pos ~len ;; external unsafe_write_assume_fd_is_nonblocking : File_descr.t -> string -> pos : int -> len : int -> int = "unix_write_assume_fd_is_nonblocking_stub" ;; let write_assume_fd_is_nonblocking fd ?pos ?len buf = let loc = "write_assume_fd_is_nonblocking" in let pos = get_opt_pos ~loc pos in let len = get_opt_len buf ~pos len in check_string_args ~loc buf ~pos ~len; unsafe_write_assume_fd_is_nonblocking fd buf ~pos ~len ;; (* Filesystem functions *) external mknod : string -> Unix.file_kind -> int -> int -> int -> unit = "unix_mknod_stub" let mknod ?(file_kind = Unix.S_REG) ?(perm = 0o600) ?(major = 0) ?(minor = 0) pathname = mknod pathname file_kind perm major minor (* Resource limits *) module RLimit = struct type limit = Limit of int64 | Infinity with sexp type t = { cur : limit; max : limit } with sexp type resource = | Core_file_size | Cpu_seconds | Data_segment | File_size | Num_file_descriptors | Stack | Virtual_memory | Nice with sexp ;; let core_file_size = Core_file_size let cpu_seconds = Cpu_seconds let data_segment = Data_segment let file_size = File_size let num_file_descriptors = Num_file_descriptors let stack = Stack let virtual_memory = IFDEF RLIMIT_AS THEN Ok Virtual_memory ELSE Or_error.unimplemented "RLIMIT_AS is not supported on this system" ENDIF let nice = IFDEF RLIMIT_NICE THEN Ok Nice ELSE Or_error.unimplemented "RLIMIT_NICE is not supported on this system" ENDIF let resource_of_sexp sexp = match resource_of_sexp sexp with | Nice -> begin match nice with | Ok resource -> resource | Error error -> of_sexp_error (Error.to_string_hum error) sexp end | Core_file_size | Cpu_seconds | Data_segment | File_size | Num_file_descriptors | Stack | Virtual_memory as resource -> resource external get : resource -> t = "unix_getrlimit" external set : resource -> t -> unit = "unix_setrlimit" let get resource = improve (fun () -> get resource) (fun () -> [("resource", sexp_of_resource resource)]) ;; let set resource t = improve (fun () -> set resource t) (fun () -> [("resource", sexp_of_resource resource); ("limit", sexp_of_t t); ]) ;; end (* Resource usage *) module Resource_usage = struct type t = { utime : float; stime : float; maxrss : int64; ixrss : int64; idrss : int64; isrss : int64; minflt : int64; majflt : int64; nswap : int64; inblock : int64; oublock : int64; msgsnd : int64; msgrcv : int64; nsignals : int64; nvcsw : int64; nivcsw : int64; } with sexp, fields external getrusage : int -> t = "unix_getrusage" let get who = getrusage (match who with `Self -> 0 | `Children -> 1) let add t1 t2 = { utime = t1.utime +. t2.utime; stime = t1.stime +. t2.stime; maxrss = Int64.(+) t1.maxrss t2.maxrss; ixrss = Int64.(+) t1.ixrss t2.ixrss; idrss = Int64.(+) t1.idrss t2.idrss; isrss = Int64.(+) t1.isrss t2.isrss; minflt = Int64.(+) t1.minflt t2.minflt; majflt = Int64.(+) t1.majflt t2.majflt; nswap = Int64.(+) t1.nswap t2.nswap; inblock = Int64.(+) t1.inblock t2.inblock; oublock = Int64.(+) t1.oublock t2.oublock; msgsnd = Int64.(+) t1.msgsnd t2.msgsnd; msgrcv = Int64.(+) t1.msgrcv t2.msgrcv; nsignals = Int64.(+) t1.nsignals t2.nsignals; nvcsw = Int64.(+) t1.nvcsw t2.nvcsw; nivcsw = Int64.(+) t1.nivcsw t2.nivcsw; } end (* System configuration *) type sysconf = | ARG_MAX | CHILD_MAX | HOST_NAME_MAX | LOGIN_NAME_MAX | OPEN_MAX | PAGESIZE | RE_DUP_MAX | STREAM_MAX | SYMLOOP_MAX | TTY_NAME_MAX | TZNAME_MAX | POSIX_VERSION | PHYS_PAGES | AVPHYS_PAGES | IOV_MAX with sexp external sysconf : sysconf -> int64 = "unix_sysconf" (* I/O vectors *) module IOVec = struct open Bigarray (* NOTE: DO NOT CHANGE THE MEMORY LAYOUT OF THIS TYPE!!! *) type 'buf t = { buf : 'buf; pos : int; len : int; } with sexp type 'buf kind = 'buf type bigstring = (char, int8_unsigned_elt, c_layout) Array1.t let string_kind = "" let bigstring_kind = Array1.create Bigarray.char c_layout 0 let empty kind = { buf = kind; pos = 0; len = 0; } let get_iovec loc ?pos ?len true_len buf = let pos = match pos with | None -> 0 | Some pos -> if pos < 0 then invalid_arg (loc ^ ": pos < 0"); pos in let len = match len with | None -> true_len | Some len -> if len < 0 then invalid_arg (loc ^ ": len < 0"); len in if pos + len > true_len then invalid_arg (loc ^ ": pos + len > length buf"); { buf = buf; pos = pos; len = len; } ;; let of_string ?pos ?len str = let str_len = String.length str in get_iovec "IOVec.of_string" ?pos ?len str_len str ;; let of_bigstring ?pos ?len bstr = let bstr_len = Array1.dim bstr in get_iovec "IOVec.of_bigstring" ?pos ?len bstr_len bstr ;; let drop iovec n = if n > iovec.len then failwith "IOVec.drop: n > length iovec" else { buf = iovec.buf; pos = iovec.pos + n; len = iovec.len - n; } ;; let max_iovecs = let n64 = sysconf IOV_MAX in if n64 > Int64.of_int Array.max_length then Array.max_length else Int64.to_int_exn n64 ;; end let get_iovec_count loc iovecs = function | None -> Array.length iovecs | Some count -> if count < 0 then invalid_arg (loc ^ ": count < 0"); let n_iovecs = Array.length iovecs in if count > n_iovecs then invalid_arg (loc ^ ": count > n_iovecs"); count ;; external unsafe_writev_assume_fd_is_nonblocking : File_descr.t -> string IOVec.t array -> int -> int = "unix_writev_assume_fd_is_nonblocking_stub" ;; let writev_assume_fd_is_nonblocking fd ?count iovecs = let count = get_iovec_count "writev_assume_fd_is_nonblocking" iovecs count in unsafe_writev_assume_fd_is_nonblocking fd iovecs count ;; external unsafe_writev : File_descr.t -> string IOVec.t array -> int -> int = "unix_writev_stub" ;; let writev fd ?count iovecs = let count = get_iovec_count "writev" iovecs count in unsafe_writev fd iovecs count ;; external pselect : File_descr.t list -> File_descr.t list -> File_descr.t list -> float -> int list -> File_descr.t list * File_descr.t list * File_descr.t list = "unix_pselect_stub" ;; (* Temporary file and directory creation *) external mkstemp : string -> string * File_descr.t = "unix_mkstemp" external mkdtemp : string -> string = "unix_mkdtemp" (* Signal handling *) external abort : unit -> 'a = "unix_abort" "noalloc" (* User id, group id management *) external initgroups : string -> int -> unit = "unix_initgroups" external getgrouplist : string -> int -> int array = "unix_getgrouplist" (** Globbing and shell word expansion *) module Fnmatch_flags = struct type _flag = [ | `No_escape | `Pathname | `Period | `File_name | `Leading_dir | `Casefold ] with sexp let flag_to_internal = function | `No_escape -> 0 | `Pathname -> 1 | `Period -> 2 | `File_name -> 3 | `Leading_dir -> 4 | `Casefold -> 5 ;; type t = int32 with sexp external internal_make : int array -> t = "unix_fnmatch_make_flags" let make = function | None | Some [] -> Int32.zero | Some flags -> internal_make (Array.map ~f:flag_to_internal (Array.of_list flags)) ;; end external fnmatch : Fnmatch_flags.t -> pat : string -> string -> bool = "unix_fnmatch" ;; let fnmatch ?flags ~pat fname = fnmatch (Fnmatch_flags.make flags) ~pat fname IFDEF WORDEXP THEN module Wordexp_flags = struct type _flag = [ `No_cmd | `Show_err | `Undef ] with sexp let flag_to_internal = function | `No_cmd -> 0 | `Show_err -> 1 | `Undef -> 2 ;; type t = int32 with sexp external internal_make : int array -> t = "unix_wordexp_make_flags" let make = function | None | Some [] -> Int32.zero | Some flags -> internal_make (Array.map ~f:flag_to_internal (Array.of_list flags)) ;; end external wordexp : Wordexp_flags.t -> string -> string array = "unix_wordexp" let wordexp = Ok (fun ?flags str -> wordexp (Wordexp_flags.make flags) str) ELSE let wordexp = Or_error.unimplemented "Unix.wordexp" ENDIF (* System information *) module Utsname = struct type t = { sysname: string; nodename: string; release: string; version: string; machine: string; } with fields, sexp end external uname : unit -> Utsname.t = "unix_uname" module Scheduler = struct module Policy = struct type t = [ `Fifo | `Round_robin | `Other ] with sexp module Ordered = struct type t = Fifo | Round_robin | Other with sexp let create = function | `Fifo -> Fifo | `Round_robin -> Round_robin | `Other -> Other ;; end end external set : pid : int -> policy : Policy.Ordered.t -> priority : int -> unit = "unix_sched_setscheduler" ;; let set ~pid ~policy ~priority = let pid = match pid with | None -> 0 | Some pid -> Pid.to_int pid in set ~pid ~policy:(Policy.Ordered.create policy) ~priority ;; end module Priority = struct external nice : int -> int = "unix_nice" end module Mman = struct module Mcl_flags = struct type t = (* Do not change the ordering of this type without also changing the C stub. *) | Current | Future with sexp end external unix_mlockall : Mcl_flags.t array -> unit = "unix_mlockall" ;; external unix_munlockall : unit -> unit = "unix_munlockall" ;; let mlockall flags = unix_mlockall (List.to_array flags) ;; let munlockall = unix_munlockall ;; end ;; let dirname_r filename = ("dirname", atom filename) let filename_r filename = ("filename", atom filename) let file_perm_r perm = ("perm", atom (Printf.sprintf "0o%o" perm)) let len_r len = ("len", Int.sexp_of_t len) let uid_r uid = ("uid", Int.sexp_of_t uid) let gid_r gid = ("gid", Int.sexp_of_t gid) let fd_r fd = ("fd", File_descr.sexp_of_t fd) let dir_handle_r handle = let fd = try File_descr.sexp_of_t (dirfd handle) with _ -> Int.sexp_of_t (-1) in ("dir_handle", fd) ;; let unary ?restart make_r f = (); fun x -> improve ?restart (fun () -> f x) (fun () -> [make_r x]) ;; let unary_fd ?restart f = unary ?restart fd_r f let unary_filename ?restart f = unary ?restart filename_r f let unary_dirname ?restart f = unary ?restart dirname_r f let unary_dir_handle ?restart f = unary ?restart dir_handle_r f include Unix_error module Syscall_result = Syscall_result exception Unix_error = Unix.Unix_error external unix_error : int -> string -> string -> _ = "unix_error_stub" let error_message = Unix.error_message let handle_unix_error f = Unix.handle_unix_error f () let environment = Unix.environment module Error = struct type t = Unix.error = | E2BIG (** Argument list too long *) | EACCES (** Permission denied *) | EAGAIN (** Resource temporarily unavailable; try again *) | EBADF (** Bad file descriptor *) | EBUSY (** Resource unavailable *) | ECHILD (** No child process *) | EDEADLK (** Resource deadlock would occur *) | EDOM (** Domain error for math functions, etc. *) | EEXIST (** File exists *) | EFAULT (** Bad address *) | EFBIG (** File too large *) | EINTR (** Function interrupted by signal *) | EINVAL (** Invalid argument *) | EIO (** Hardware I/O error *) | EISDIR (** Is a directory *) | EMFILE (** Too many open files by the process *) | EMLINK (** Too many links *) | ENAMETOOLONG (** Filename too long *) | ENFILE (** Too many open files in the system *) | ENODEV (** No such device *) | ENOENT (** No such file or directory *) | ENOEXEC (** Not an executable file *) | ENOLCK (** No locks available *) | ENOMEM (** Not enough memory *) | ENOSPC (** No space left on device *) | ENOSYS (** Function not supported *) | ENOTDIR (** Not a directory *) | ENOTEMPTY (** Directory not empty *) | ENOTTY (** Inappropriate I/O control operation *) | ENXIO (** No such device or address *) | EPERM (** Operation not permitted *) | EPIPE (** Broken pipe *) | ERANGE (** Result too large *) | EROFS (** Read-only file system *) | ESPIPE (** Invalid seek e.g. on a pipe *) | ESRCH (** No such process *) | EXDEV (** Invalid link *) | EWOULDBLOCK (** Operation would block *) | EINPROGRESS (** Operation now in progress *) | EALREADY (** Operation already in progress *) | ENOTSOCK (** Socket operation on non-socket *) | EDESTADDRREQ (** Destination address required *) | EMSGSIZE (** Message too long *) | EPROTOTYPE (** Protocol wrong type for socket *) | ENOPROTOOPT (** Protocol not available *) | EPROTONOSUPPORT (** Protocol not supported *) | ESOCKTNOSUPPORT (** Socket type not supported *) | EOPNOTSUPP (** Operation not supported on socket *) | EPFNOSUPPORT (** Protocol family not supported *) | EAFNOSUPPORT (** Address family not supported by protocol family *) | EADDRINUSE (** Address already in use *) | EADDRNOTAVAIL (** Can't assign requested address *) | ENETDOWN (** Network is down *) | ENETUNREACH (** Network is unreachable *) | ENETRESET (** Network dropped connection on reset *) | ECONNABORTED (** Software caused connection abort *) | ECONNRESET (** Connection reset by peer *) | ENOBUFS (** No buffer space available *) | EISCONN (** Socket is already connected *) | ENOTCONN (** Socket is not connected *) | ESHUTDOWN (** Can't send after socket shutdown *) | ETOOMANYREFS (** Too many references: can't splice *) | ETIMEDOUT (** Connection timed out *) | ECONNREFUSED (** Connection refused *) | EHOSTDOWN (** Host is down *) | EHOSTUNREACH (** No route to host *) | ELOOP (** Too many levels of symbolic links *) | EOVERFLOW (** File size or position not representable *) | EUNKNOWNERR of int (** Unknown error *) with sexp let of_system_int ~errno = Unix_error.of_errno errno let message = Unix.error_message end let putenv ~key ~data = improve (fun () -> Unix.putenv key data) (fun () -> [("key", atom key); ("data", atom data)]) ;; let unsetenv name = (* The C unsetenv has only one error: EINVAL if name contains an '=' character. C strings are null terminated though so '\000' is also invalid. *) if String.contains name '\000' then raise (Unix_error (EINVAL,"unsetenv",name)); unsetenv name ;; type process_status = Unix.process_status = | WEXITED of int | WSIGNALED of int | WSTOPPED of int with sexp module Exit = struct type error = [ `Exit_non_zero of int ] with compare, sexp type t = (unit, error) Result.t with compare, sexp let to_string_hum = function | Ok () -> "exited normally" | Error (`Exit_non_zero i) -> sprintf "exited with code %d" i ;; let code = function | Ok () -> 0 | Error (`Exit_non_zero i) -> i ;; exception Exit_code_must_be_nonnegative of int with sexp let of_code code = if code < 0 then raise (Exit_code_must_be_nonnegative code) else if code = 0 then Ok () else Error (`Exit_non_zero code) ;; let or_error = function | Ok _ as ok -> ok | Error error -> Or_error.error "Unix.Exit" error sexp_of_error ;; end module Exit_or_signal = struct type error = [ Exit.error | `Signal of Signal.t ] with compare, sexp type t = (unit, error) Result.t with compare, sexp let to_string_hum = function | Ok () | Error #Exit.error as e -> Exit.to_string_hum e | Error (`Signal s) -> sprintf "died after receiving %s (signal number %d)" (Signal.to_string s) (Signal.to_system_int s) ;; exception Of_unix_got_invalid_status of process_status with sexp let of_unix = function | WEXITED i -> if i = 0 then Ok () else Error (`Exit_non_zero i) | WSIGNALED i -> Error (`Signal (Signal.of_caml_int i)) | WSTOPPED _ as status -> raise (Of_unix_got_invalid_status status) ;; let or_error = function | Ok _ as ok -> ok | Error error -> Or_error.error "Unix.Exit_or_signal" error sexp_of_error ;; end module Exit_or_signal_or_stop = struct type error = [ Exit_or_signal.error | `Stop of Signal.t ] with sexp type t = (unit, error) Result.t with sexp let to_string_hum = function | Ok () | Error #Exit_or_signal.error as e -> Exit_or_signal.to_string_hum e | Error (`Stop s) -> sprintf "stopped by %s (signal number %d)" (Signal.to_string s) (Signal.to_system_int s) ;; let of_unix = function | WEXITED i -> if i = 0 then Ok () else Error (`Exit_non_zero i) | WSIGNALED i -> Error (`Signal (Signal.of_caml_int i)) | WSTOPPED i -> Error (`Stop (Signal.of_caml_int i)) ;; let or_error = function | Ok _ as ok -> ok | Error error -> Or_error.error "Unix.Exit_or_signal_or_stop" error sexp_of_error ;; end let prog_r prog = ("prog", atom prog) let args_r args = ("args", sexp_of_array atom args) let env_r env = ("env", sexp_of_array atom env) let execv ~prog ~args = improve (fun () -> Unix.execv ~prog ~args) (fun () -> [prog_r prog; args_r args]) ;; let execve ~prog ~args ~env = improve (fun () -> Unix.execve ~prog ~args ~env) (fun () -> [prog_r prog; args_r args; env_r env]) ;; let execvp ~prog ~args = improve (fun () -> Unix.execvp ~prog ~args) (fun () -> [prog_r prog; args_r args]) ;; let execvpe ~prog ~args ~env = improve (fun () -> Unix.execvpe ~prog ~args ~env) (fun () -> [prog_r prog; args_r args; env_r env]) ;; type env = [ `Replace of (string * string) list | `Extend of (string * string) list | `Replace_raw of string list ] with sexp let env_assignments env = match env with | `Replace_raw env -> env | (`Replace _ | `Extend _) as env -> let env_map = let current, env = match env with | `Replace env -> [], env | `Extend env -> let current = List.map (Array.to_list (Unix.environment ())) ~f:(fun s -> String.lsplit2_exn s ~on:'=') in current, env in List.fold_left (current @ env) ~init:String.Map.empty ~f:(fun map (key, data) -> Map.add map ~key ~data) in Map.fold env_map ~init:[] ~f:(fun ~key ~data acc -> (key ^ "=" ^ data) :: acc) let exec ~prog ~args ?(use_path = true) ?env () = let args = Array.of_list args in let env = Option.map env ~f:(Fn.compose Array.of_list env_assignments) in match use_path, env with | false, None -> execv ~prog ~args | false, Some env -> execve ~prog ~args ~env | true, None -> execvp ~prog ~args | true, Some env -> execvpe ~prog ~args ~env ;; exception Fork_returned_negative_result of int with sexp let fork () = let pid = Unix.fork () in if pid < 0 then raise (Fork_returned_negative_result pid) else if pid = 0 then `In_the_child else `In_the_parent (Pid.of_int pid) ;; let fork_exec ~prog ~args ?use_path ?env () = match fork () with | `In_the_child -> never_returns (exec ~prog ~args ?use_path ?env ()) | `In_the_parent pid -> pid ;; type wait_flag = Unix.wait_flag = | WNOHANG | WUNTRACED with sexp type wait_on = [ `Any | `My_group | `Group of Pid.t | `Pid of Pid.t ] with sexp type mode = wait_flag list with sexp_of type _t = mode type waitpid_result = (Pid.t * Exit_or_signal_or_stop.t) option with sexp_of let wait_gen ~mode (type a) (f : waitpid_result -> a option) ~restart wait_on : a = let pid = match wait_on with | `Any -> -1 | `Group pid -> - (Pid.to_int pid) | `My_group -> 0 | `Pid pid -> Pid.to_int pid in let (pid, status) = improve ~restart (fun () -> let x, ps = Unix.waitpid ~mode pid in (x, Exit_or_signal_or_stop.of_unix ps)) (fun () -> [("mode", sexp_of_list sexp_of_wait_flag mode); ("pid", Int.sexp_of_t pid)]) in let waitpid_result = if pid = 0 then None else begin let pid = Pid.of_int pid in Some (pid, status) end in match f waitpid_result with | Some a -> a | None -> failwiths "waitpid syscall returned invalid result for mode" (pid, mode, waitpid_result) (<:sexp_of< int * mode * waitpid_result >>) ;; let wait ?(restart=true) pid = let f = function | Some ((_, (Ok _ | Error #Exit_or_signal.error)) as x) -> Some x | _ -> None in wait_gen ~restart ~mode:[] f pid ;; let wait_nohang pid = let f = function | None | Some ((_, (Ok _ | Error #Exit_or_signal.error))) as x -> Some x | _ -> None in wait_gen ~mode:[WNOHANG] ~restart:true f pid ;; let wait_untraced ?(restart=true) pid = wait_gen ~restart ~mode:[WUNTRACED] Fn.id pid let wait_nohang_untraced pid = wait_gen ~mode:[WNOHANG; WUNTRACED] Option.some ~restart:true pid let waitpid pid = let (pid', exit_or_signal) = wait (`Pid pid) in assert (pid = pid'); exit_or_signal; ;; let waitpid_exn pid = let exit_or_signal = waitpid pid in if Result.is_error exit_or_signal then failwiths "child process didn't exit with status zero" (`Child_pid pid, exit_or_signal) (<:sexp_of< [ `Child_pid of Pid.t ] * Exit_or_signal.t >>) ;; let system s = improve (fun () -> Exit_or_signal.of_unix (Unix.system s)) (fun () -> [("command", atom s)]) ;; let getpid () = Pid.of_int (Unix.getpid ()) let getppid () = match Unix.getppid () with | x when x < 1 -> None | x -> Some (Pid.of_int x) let getppid_exn () = Option.value_exn ~message:"You don't have a parent process" (getppid ()) module Thread_id = Int IFDEF THREAD_ID THEN external gettid : unit -> Thread_id.t = "unix_gettid" let gettid = Ok gettid ELSE let gettid = Or_error.unimplemented "gettid is not supported on this system" ENDIF let nice i = improve (fun () -> Unix.nice i) (fun () -> [("priority", Int.sexp_of_t i)]) ;; let stdin = Unix.stdin let stdout = Unix.stdout let stderr = Unix.stderr type open_flag = Unix.open_flag = | O_RDONLY | O_WRONLY | O_RDWR | O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC | O_EXCL | O_NOCTTY | O_DSYNC | O_SYNC | O_RSYNC | O_SHARE_DELETE | O_CLOEXEC with sexp type file_perm = int with of_sexp (* Prints out in octal, which is much more standard in Unix. *) let sexp_of_file_perm fp = Sexp.Atom (Printf.sprintf "0o%03o" fp) let is_rw_open_flag = function O_RDONLY | O_WRONLY | O_RDWR -> true | _ -> false let openfile ?(perm = 0o644) ~mode filename = let mode_sexp () = sexp_of_list sexp_of_open_flag mode in if not (List.exists mode ~f:is_rw_open_flag) then failwithf "Unix.openfile: no read or write flag specified in mode: %s" (Sexp.to_string (mode_sexp ())) () else improve (fun () -> Unix.openfile filename ~mode ~perm) (fun () -> [filename_r filename; ("mode", mode_sexp ()); file_perm_r perm]) ;; let close ?restart = unary_fd ?restart Unix.close let with_close fd ~f = protect ~f:(fun () -> f fd) ~finally:(fun () -> close fd) let with_file ?perm file ~mode ~f = with_close (openfile file ~mode ?perm) ~f let read_write f ?restart ?pos ?len fd ~buf = let pos, len = Core_kernel.Ordered_collection_common.get_pos_len_exn ?pos ?len ~length:(String.length buf) in improve ?restart (fun () -> f fd ~buf ~pos ~len) (fun () -> [fd_r fd; ("pos", Int.sexp_of_t pos); len_r len]) ;; let read = read_write Unix.read let write = read_write Unix.write ?restart:None let single_write = read_write Unix.single_write let in_channel_of_descr = Unix.in_channel_of_descr let out_channel_of_descr = Unix.out_channel_of_descr let descr_of_in_channel = Unix.descr_of_in_channel let descr_of_out_channel = Unix.descr_of_out_channel type seek_command = Unix.seek_command = | SEEK_SET | SEEK_CUR | SEEK_END with sexp type file_kind = Unix.file_kind = | S_REG | S_DIR | S_CHR | S_BLK | S_LNK | S_FIFO | S_SOCK with sexp let isatty = unary_fd Unix.isatty module Native_file = struct type stats = Unix.stats = { st_dev : int; st_ino : int; st_kind : file_kind; st_perm : file_perm; st_nlink : int; st_uid : int; st_gid : int; st_rdev : int; st_size : int; st_atime : float; st_mtime : float; st_ctime : float; } with sexp let stat = unary_filename Unix.stat let lstat = unary_filename Unix.lstat let fstat = unary_fd Unix.fstat let lseek fd pos ~mode = improve (fun () -> Unix.lseek fd pos ~mode) (fun () -> [fd_r fd; ("pos", Int.sexp_of_t pos); ("mode", sexp_of_seek_command mode)]) ;; let truncate filename ~len = improve (fun () -> Unix.truncate filename ~len) (fun () -> [filename_r filename; len_r len]) ;; let ftruncate fd ~len = improve (fun () -> Unix.ftruncate fd ~len) (fun () -> [fd_r fd; len_r len]) ;; end type lock_command = Unix.lock_command = | F_ULOCK | F_LOCK | F_TLOCK | F_TEST | F_RLOCK | F_TRLOCK with sexp let lockf fd ~mode ~len = let len = try Int64.to_int_exn len with _ -> failwith "~len passed to Unix.lockf too large to fit in native int" in improve (fun () -> Unix.lockf fd ~mode ~len) (fun () -> [fd_r fd; ("mode", sexp_of_lock_command mode); len_r len]) ;; module Flock_command : sig type t val lock_shared : t val lock_exclusive : t val unlock : t end = struct type t = int (* The constants are used in the [core_unix_flock] C code. *) let lock_shared = 0 let lock_exclusive = 1 let unlock = 2 end external flock : File_descr.t -> Flock_command.t -> bool = "core_unix_flock" let lseek fd pos ~mode = improve (fun () -> Unix.LargeFile.lseek fd pos ~mode) (fun () -> [fd_r fd; ("pos", Int64.sexp_of_t pos); ("mode", sexp_of_seek_command mode)]) ;; let len64_r len = ("len", Int64.sexp_of_t len) let truncate filename ~len = improve (fun () -> Unix.LargeFile.truncate filename ~len) (fun () -> [filename_r filename; len64_r len]) ;; let ftruncate fd ~len = improve (fun () -> Unix.LargeFile.ftruncate fd ~len) (fun () -> [fd_r fd; len64_r len]) ;; type stats = Unix.LargeFile.stats = { st_dev : int; st_ino : int; st_kind : file_kind; st_perm : file_perm; st_nlink : int; st_uid : int; st_gid : int; st_rdev : int; st_size : int64; st_atime : float; st_mtime : float; st_ctime : float; } with sexp external stat : string -> stats = "core_unix_stat_64" let stat = unary_filename stat external lstat : string -> stats = "core_unix_lstat_64" let lstat = unary_filename lstat external fstat : File_descr.t -> stats = "core_unix_fstat_64" let fstat = unary_fd fstat let src_dst f ~src ~dst = improve (fun () -> f ~src ~dst) (fun () -> [("src", atom src); ("dst", atom dst)]) ;; let unlink = unary_filename Unix.unlink let rename = src_dst Unix.rename let link ?(force = false) ~target ~link_name () = improve (fun () -> if force then begin try Unix.unlink link_name with Unix_error (Unix.ENOENT, _, _) -> () end; Unix.link ~src:target ~dst:link_name) (fun () -> [("target", atom target); ("link_name", atom link_name)]) ;; type access_permission = Unix.access_permission = | R_OK | W_OK | X_OK | F_OK with sexp let chmod filename ~perm = improve (fun () -> Unix.chmod filename ~perm) (fun () -> [filename_r filename; file_perm_r perm]) ;; let fchmod fd ~perm = improve (fun () -> Unix.fchmod fd ~perm) (fun () -> [fd_r fd; file_perm_r perm]) ;; let chown filename ~uid ~gid = improve (fun () -> Unix.chown filename ~uid ~gid) (fun () -> [filename_r filename; uid_r uid; gid_r gid]) ;; let fchown fd ~uid ~gid = improve (fun () -> Unix.fchown fd ~uid ~gid) (fun () -> [fd_r fd; uid_r uid; gid_r gid]) ;; let umask mode = improve (fun () -> Unix.umask mode) (fun () -> [("mode", atom (Printf.sprintf "0o%o" mode))]) ;; let access filename ~perm = improve (fun () -> Unix.access filename ~perm) (fun () -> [filename_r filename; ("perm", sexp_of_list sexp_of_access_permission perm)]) ;; let access filename perm = Result.try_with (fun () -> access filename ~perm:(List.map perm ~f:(function | `Read -> Unix.R_OK | `Write -> Unix.W_OK | `Exec -> Unix.X_OK | `Exists -> Unix.F_OK))) ;; let access_exn filename perm = Result.ok_exn (access filename perm) external remove : string -> unit = "core_unix_remove" let remove = unary_filename remove TEST = let dir = Core_filename.temp_dir "remove_test" "" in let file = dir ^/ "test" in Out_channel.write_all (dir ^ "/test") ~data:"testing Core.Unix.remove"; remove file; remove dir; Result.is_error (access file [`Exists]) && Result.is_error (access dir [`Exists]) let dup = unary_fd Unix.dup let dup2 ~src ~dst = improve (fun () -> Unix.dup2 ~src ~dst) (fun () -> [("src", File_descr.sexp_of_t src); ("dst", File_descr.sexp_of_t dst)]) ;; TEST_UNIT "fork_exec ~env last binding takes precedence" = protectx ~finally:remove (Filename.temp_file "test" "fork_exec.env.last-wins") ~f:(fun temp_file -> let env = [ "VAR", "first"; "VAR", "last" ] in List.iter [ `Replace_raw (List.map env ~f:(fun (v, s) -> v ^ "=" ^ s)) ; `Replace env ; `Extend env ] ~f:(fun env -> waitpid_exn (fork_exec () ~env ~prog:"sh" ~args:[ "sh"; "-c"; "echo $VAR > " ^ temp_file ]); <:test_result< string >> ~expect:"last\n" (In_channel.read_all temp_file))) let set_nonblock = unary_fd Unix.set_nonblock let clear_nonblock = unary_fd Unix.clear_nonblock let set_close_on_exec = unary_fd Unix.set_close_on_exec let clear_close_on_exec = unary_fd Unix.clear_close_on_exec module Open_flags = struct external append : unit -> Int63.t = "unix_O_APPEND" external async : unit -> Int63.t = "unix_O_ASYNC" external cloexec : unit -> Int63.t = "unix_O_CLOEXEC" external creat : unit -> Int63.t = "unix_O_CREAT" external direct : unit -> Int63.t = "unix_O_DIRECT" external directory : unit -> Int63.t = "unix_O_DIRECTORY" external dsync : unit -> Int63.t = "unix_O_DSYNC" external excl : unit -> Int63.t = "unix_O_EXCL" external noatime : unit -> Int63.t = "unix_O_NOATIME" external noctty : unit -> Int63.t = "unix_O_NOCTTY" external nofollow : unit -> Int63.t = "unix_O_NOFOLLOW" external nonblock : unit -> Int63.t = "unix_O_NONBLOCK" external rdonly : unit -> Int63.t = "unix_O_RDONLY" external rdwr : unit -> Int63.t = "unix_O_RDWR" external rsync : unit -> Int63.t = "unix_O_RSYNC" external sync : unit -> Int63.t = "unix_O_SYNC" external trunc : unit -> Int63.t = "unix_O_TRUNC" external wronly : unit -> Int63.t = "unix_O_WRONLY" let append = append () let async = async () let cloexec = cloexec () let creat = creat () let direct = direct () let directory = directory () let dsync = dsync () let excl = excl () let noatime = noatime () let noctty = noctty () let nofollow = nofollow () let nonblock = nonblock () let rdonly = rdonly () let rdwr = rdwr () let rsync = rsync () let sync = sync () let trunc = trunc () let wronly = wronly () let known = [ append, "append"; async, "async"; cloexec, "cloexec"; creat, "creat"; direct, "direct"; directory, "directory"; dsync, "dsync"; excl, "excl"; noatime, "noatime"; noctty, "noctty"; nofollow, "nofollow"; nonblock, "nonblock"; rsync, "rsync"; sync, "sync"; trunc, "trunc"; (* We handle the access modes separately from the standard [Flags.sexp_of_t], because they are multibit and include the [rdonly] flag, which is zero, which [Flags] doesn't allow. *) ] ;; let access_modes = [ rdonly, "rdonly"; rdwr, "rdwr"; wronly, "wronly"; ] ;; include Flags.Make (struct let allow_intersecting = true let should_print_error = true let known = known let remove_zero_flags = true (* remove non existing flags, like cloexec on centos5 *) end) (* The lower two bits of the open flags are used to specify the access mode: rdonly, wronly, rdwr. So, we have some code to treat those two bits together rather than as two separate bit flags. *) let access_mode t = Int63.bit_and t (Int63.of_int 3) let can_read t = access_mode t = rdonly || access_mode t = rdwr TEST = can_read rdonly TEST = can_read rdwr TEST = not (can_read wronly) let can_write t = access_mode t = wronly || access_mode t = rdwr TEST = can_write wronly TEST = can_write rdwr TEST = not (can_write rdonly) let sexp_of_t t = let a = access_mode t in let t, prefix = match List.find access_modes ~f:(fun (a', _) -> a = a') with | None -> t, [] | Some (_, name) -> t - a, [Sexp.Atom name] in let rest = match sexp_of_t t with | Sexp.Atom _ as s -> [s] | Sexp.List l -> l in Sexp.List (prefix @ rest) ;; let check t string = let sexp1 = sexp_of_t t in let sexp2 = Sexp.of_string string in if Sexp.(<>) sexp1 sexp2 then failwiths "unequal sexps" (sexp1, sexp2) <:sexp_of< Sexp.t * Sexp.t >>; ;; TEST_UNIT = check rdonly "(rdonly)" TEST_UNIT = check wronly "(wronly)" TEST_UNIT = check rdwr "(rdwr)" TEST_UNIT = check append "(rdonly append)" TEST_UNIT = check (wronly + append) "(wronly append)" end let fcntl_getfl, fcntl_setfl = let module M = struct external unix_fcntl : Unix.file_descr -> Int63.t -> Int63.t -> Int63.t = "unix_fcntl" external getfl : unit -> Int63.t = "unix_F_GETFL" external setfl : unit -> Int63.t = "unix_F_SETFL" let getfl = getfl () let setfl = setfl () end in let open M in let fcntl_getfl fd = unix_fcntl fd getfl Int63.zero in let fcntl_setfl fd flags = let result = unix_fcntl fd setfl flags in (* [unix_fcntl] raised if there was an error, so if we're here, it must have returned zero. *) assert (result = Int63.zero); in fcntl_getfl, fcntl_setfl ;; TEST_UNIT = let test = "unix_test_file" in let rm_test () = try unlink test with _ -> () in rm_test (); let fd = openfile test ~mode:[O_CREAT; O_WRONLY] in let flags = fcntl_getfl fd in assert (Open_flags.do_intersect flags Open_flags.wronly); assert (Open_flags.are_disjoint flags Open_flags.append); fcntl_setfl fd (Open_flags.(+) flags Open_flags.append); assert (Open_flags.do_intersect (fcntl_getfl fd) Open_flags.append); rm_test (); ;; let mkdir ?(perm=0o777) dirname = improve (fun () -> Unix.mkdir dirname ~perm) (fun () -> [dirname_r dirname; file_perm_r perm]) ;; let mkdir_p ?perm dirname = let mkdir_if_missing ?perm dir = try mkdir ?perm dir with (* [mkdir] on MacOSX returns [EISDIR] instead of [EEXIST] if the directory already exists. *) | Unix_error ((EEXIST | EISDIR), _, _) -> () | e -> raise e in let init,dirs = match Core_filename.parts dirname with | [] -> assert false | init :: dirs -> (init, dirs) in mkdir_if_missing ?perm init; let (_:string) = (* just using the fold for the side effects and accumulator *) (* This must be [fold_left], not [fold_right]. *) List.fold_left dirs ~init ~f:(fun acc dir -> let dir = Filename.concat acc dir in mkdir_if_missing ?perm dir; dir) in () ;; let rmdir = unary_dirname Unix.rmdir let chdir = unary_dirname Unix.chdir let getcwd = Unix.getcwd let chroot = unary_dirname Unix.chroot type dir_handle = Unix.dir_handle let opendir ?restart = unary_dirname ?restart Unix.opendir let readdir = unary_dir_handle Unix.readdir (* Non-intr *) let rewinddir = unary_dir_handle Unix.rewinddir (* Non-intr *) (* if closedir is passed an already closed file handle it will try to call dirfd on it to get a file descriptor for the error message, which will fail with invalid argument because closedir sets the fd to null *) let closedir = (* Non-intr *) unary_dir_handle (fun dh -> try Unix.closedir dh with | Invalid_argument _ -> ()) let pipe = Unix.pipe let mkfifo name ~perm = improve (fun () -> Unix.mkfifo name ~perm) (fun () -> [("name", atom name); file_perm_r perm]) ;; module Process_info = struct (* Any change to the order of these fields must be accompanied by a corresponding change to unix_stubs.c:ml_create_process. *) type t = { pid : Pid.t; stdin : File_descr.t; stdout : File_descr.t; stderr : File_descr.t; } with sexp end external create_process : ?working_dir : string -> prog : string -> args : string array -> env : string array -> search_path : bool -> Process_info.t = "ml_create_process" let create_process_env ?working_dir ~prog ~args ~env () = create_process ?working_dir ~search_path:true ~prog ~args:(Array.of_list args) ~env:(Array.of_list (env_assignments env)) let create_process_env ?working_dir ~prog ~args ~env () = improve (fun () -> create_process_env ?working_dir ~prog ~args ~env ()) (fun () -> [("prog", atom prog); ("args", sexp_of_list atom args); ("env", sexp_of_env env)]) let create_process ~prog ~args = improve (fun () -> create_process_env ~prog ~args ~env:(`Extend []) ()) (fun () -> [("prog", atom prog); ("args", sexp_of_list atom args)]) let make_open_process f command = improve (fun () -> f command) (fun () -> [("command", atom command)]) let open_process_in = make_open_process Unix.open_process_in let open_process_out = make_open_process Unix.open_process_out let open_process = make_open_process Unix.open_process module Process_channels = struct type t = { stdin : out_channel; stdout : in_channel; stderr : in_channel; } end let open_process_full command ~env = improve (fun () -> let stdout, stdin, stderr = Unix.open_process_full command ~env in { Process_channels.stdin = stdin; stdout = stdout; stderr = stderr }) (fun () -> [("command", atom command); ("env", sexp_of_array atom env)]) ;; let close_process_in ic = Exit_or_signal.of_unix (Unix.close_process_in ic) let close_process_out oc = Exit_or_signal.of_unix (Unix.close_process_out oc) let close_process (ic, oc) = Exit_or_signal.of_unix (Unix.close_process (ic, oc)) let close_process_full c = let module C = Process_channels in Exit_or_signal.of_unix (Unix.close_process_full (c.C.stdout, c.C.stdin, c.C.stderr)) ;; let symlink = src_dst Unix.symlink let readlink = unary_filename Unix.readlink module Select_fds = struct type t = { read : File_descr.t list; write : File_descr.t list; except : File_descr.t list; } with sexp_of let empty = { read = []; write = []; except = [] } end type select_timeout = [ `Never | `Immediately | `After of Time_ns.Span.t ] with sexp_of let select ?restart ~read ~write ~except ~timeout () = improve ?restart (fun () -> let timeout = match timeout with | `Never -> -1. | `Immediately -> 0. | `After span -> if Time_ns.Span.( < ) span Time_ns.Span.zero then 0. else Time_ns.Span.to_sec span in let read, write, except = Unix.select ~read ~write ~except ~timeout in { Select_fds. read; write; except }) (fun () -> [("read", sexp_of_list File_descr.sexp_of_t read); ("write", sexp_of_list File_descr.sexp_of_t write); ("except", sexp_of_list File_descr.sexp_of_t except); ("timeout", <:sexp_of< select_timeout >> timeout)]) ;; let pause = Unix.pause type process_times = Unix.process_times = { tms_utime : float; tms_stime : float; tms_cutime : float; tms_cstime : float; } with sexp type tm = Unix.tm = { (* DON'T CHANGE THIS RECORD WITHOUT UPDATING unix_time_stubs.c!!! The compiler will notice if the runtime's Unix.tm changes, and we must then update unix_time_stubs.c, not just this copy of the definition. *) tm_sec : int; tm_min : int; tm_hour : int; tm_mday : int; tm_mon : int; tm_year : int; tm_wday : int; tm_yday : int; tm_isdst : bool; } with sexp let time = Unix.time let gettimeofday = Unix.gettimeofday external strftime : Unix.tm -> string -> string = "core_time_ns_strftime" external localtime : float -> Unix.tm = "core_localtime" external gmtime : float -> Unix.tm = "core_gmtime" external timegm : Unix.tm -> float = "core_timegm" (* the inverse of gmtime *) let mktime = Unix.mktime let alarm = Unix.alarm let sleep = Unix.sleep let times = Unix.times let utimes = Unix.utimes external strptime : fmt:string -> string -> Unix.tm = "unix_strptime" TEST_UNIT "record format hasn't changed" = (* Exclude the time zone (%Z) because it depends on the location. *) <:test_result< string >> ~expect:"1907-07-05 04:03:08; wday=2; yday=010" (strftime { tm_sec = 8; tm_min = 3; tm_hour = 4; tm_mday = 5; tm_mon = 6; tm_year = 7; tm_wday = 2; tm_yday = 9; tm_isdst = true } "%F %T; wday=%u; yday=%j") TEST = let res = strptime ~fmt:"%Y-%m-%d %H:%M:%S" "2012-05-23 10:14:23" in let res = (* fill in optional fields if they are missing *) let tm_wday = if res.Unix.tm_wday = 0 then 3 else res.Unix.tm_wday in let tm_yday = if res.Unix.tm_yday = 0 then 143 else res.Unix.tm_yday in { res with Unix. tm_wday; tm_yday } in res = {Unix. tm_sec = 23; tm_min = 14; tm_hour = 10; tm_mday = 23; tm_mon = 4; tm_year = 2012 - 1900; tm_wday = 3; tm_yday = 143; tm_isdst = false; } TEST = try ignore (strptime ~fmt:"%Y-%m-%d" "2012-05-"); false with | _ -> true type interval_timer = Unix.interval_timer = | ITIMER_REAL | ITIMER_VIRTUAL | ITIMER_PROF with sexp type interval_timer_status = Unix.interval_timer_status = { it_interval : float; it_value : float; } with sexp let getitimer = Unix.getitimer let setitimer = Unix.setitimer let getuid = Unix.getuid let geteuid = Unix.geteuid let setuid uid = improve (fun () -> Unix.setuid uid) (fun () -> [("uid", Int.sexp_of_t uid)]) let getgid = Unix.getgid let getegid = Unix.getegid let setgid gid = improve (fun () -> Unix.setgid gid) (fun () -> [("gid", Int.sexp_of_t gid)]) let getgroups = Unix.getgroups let make_by f make_exn = let normal arg = try Some (f arg) with Not_found -> None in let exn arg = try f arg with Not_found -> raise (make_exn arg) in (normal, exn) ;; module Passwd = struct type t = { name : string; passwd : string; uid : int; gid : int; gecos : string; dir : string; shell : string; } with sexp let of_unix u = let module U = Unix in { name = u.U.pw_name; passwd = u.U.pw_passwd; uid = u.U.pw_uid; gid = u.U.pw_gid; gecos = u.U.pw_gecos; dir = u.U.pw_dir; shell = u.U.pw_shell; } ;; exception Getbyname of string with sexp let (getbyname, getbyname_exn) = make_by (fun name -> of_unix (Unix.getpwnam name)) (fun s -> Getbyname s) ;; exception Getbyuid of int with sexp let (getbyuid, getbyuid_exn) = make_by (fun uid -> of_unix (Unix.getpwuid uid)) (fun s -> Getbyuid s) ;; exception Getpwent with sexp module Low_level = struct external core_setpwent : unit -> unit = "core_setpwent" ;; external core_endpwent : unit -> unit = "core_endpwent" ;; external core_getpwent : unit -> Unix.passwd_entry = "core_getpwent" ;; let setpwent = core_setpwent ;; let getpwent_exn () = of_unix (core_getpwent ()) ;; let getpwent () = Option.try_with (fun () -> getpwent_exn ()) ;; let endpwent = core_endpwent ;; end ;; let pwdb_lock = Mutex0.create () ;; let getpwents () = Mutex0.critical_section pwdb_lock ~f:(fun () -> Low_level.setpwent (); Exn.protect ~f:(fun () -> let rec loop acc = try let ent = Low_level.getpwent_exn () in loop (ent :: acc) with | End_of_file -> List.rev acc in loop [])) ~finally:(fun () -> Low_level.endpwent ()) ;; end module Group = struct type t = { name : string; passwd : string; gid : int; mem : string array; } with sexp_of let of_unix u = { name = u.Unix.gr_name; passwd = u.Unix.gr_passwd; gid = u.Unix.gr_gid; mem = u.Unix.gr_mem; } ;; exception Getbyname of string with sexp let (getbyname, getbyname_exn) = make_by (fun name -> of_unix (Unix.getgrnam name)) (fun s -> Getbyname s) ;; exception Getbygid of int with sexp let (getbygid, getbygid_exn) = make_by (fun gid -> of_unix (Unix.getgrgid gid)) (fun s -> Getbygid s) ;; end (* The standard getlogin function goes through utmp which is unreliable, see the BUGS section of getlogin(3) *) let _getlogin_orig = Unix.getlogin let getlogin () = (Unix.getpwuid (getuid ())).Unix.pw_name module Protocol_family = struct type t = [ `Unix | `Inet | `Inet6 ] with bin_io, sexp let of_unix = function | Unix.PF_UNIX -> `Unix | Unix.PF_INET -> `Inet | Unix.PF_INET6 -> `Inet6 ;; end let gethostname = Unix.gethostname module Inet_addr0 = struct module T = struct type t = Unix.inet_addr let of_string = Unix.inet_addr_of_string let to_string = Unix.string_of_inet_addr (* Unix.inet_addr is represented as either a "struct in_addr" or a "struct in6_addr" stuffed into an O'Caml string, so polymorphic compare will work *) let compare = Pervasives.compare let sexp_of_t t = Sexp.Atom (to_string t) let t_of_sexp = function | Sexp.Atom s -> of_string s | Sexp.List _ as sexp -> of_sexp_error "Inet_addr0.t_of_sexp: atom expected" sexp end include T include Comparable.Make(T) end module Host = struct type t = { name : string; aliases : string array; family : Protocol_family.t; addresses : Inet_addr0.t array; } with sexp_of let of_unix u = { name = u.Unix.h_name; aliases = u.Unix.h_aliases; family = Protocol_family.of_unix u.Unix.h_addrtype; addresses = u.Unix.h_addr_list; } ;; exception Getbyname of string with sexp let (getbyname, getbyname_exn) = make_by (fun name -> of_unix (Unix.gethostbyname name)) (fun s -> Getbyname s) ;; exception Getbyaddr of Inet_addr0.t with sexp let (getbyaddr, getbyaddr_exn) = make_by (fun addr -> of_unix (Unix.gethostbyaddr addr)) (fun a -> Getbyaddr a) ;; let have_address_in_common h1 h2 = let addrs1 = Inet_addr0.Set.of_array h1.addresses in let addrs2 = Inet_addr0.Set.of_array h2.addresses in not (Inet_addr0.Set.is_empty (Inet_addr0.Set.inter addrs1 addrs2)) ;; end module Inet_addr = struct include Inet_addr0 include (Binable.Of_stringable (Inet_addr0) : Binable.S with type t := t) exception Get_inet_addr of string * string with sexp let of_string_or_getbyname name = try of_string name with Failure _ -> match Host.getbyname name with | None -> raise (Get_inet_addr (name, "host not found")) | Some host -> match host.Host.family with | `Unix -> assert false (* impossible *) | `Inet | `Inet6 -> let addrs = host.Host.addresses in if Int.(>) (Array.length addrs) 0 then addrs.(0) else raise (Get_inet_addr (name, "empty addrs")) ;; let t_of_sexp = function | Sexp.Atom name -> of_string_or_getbyname name | Sexp.List _ as sexp -> of_sexp_error "Inet_addr.t_of_sexp: atom expected" sexp ;; let bind_any = Unix.inet_addr_any let bind_any_inet6 = Unix.inet6_addr_any let localhost = Unix.inet_addr_loopback let localhost_inet6 = Unix.inet6_addr_loopback let inet4_addr_of_int32 l = let lower_24 = Int32.(to_int_exn (bit_and l (of_int_exn 0xFF_FFFF))) in let upper_8 = Int32.(to_int_exn (shift_right_logical l 24)) in of_string (sprintf "%d.%d.%d.%d" (upper_8 land 0xFF) (lower_24 lsr 16 land 0xFF) (lower_24 lsr 8 land 0xFF) (lower_24 land 0xFF)) let inet4_addr_to_int32_exn addr = let addr_s = to_string addr in match String.split ~on:'.' addr_s |! List.map ~f:(fun s -> let i = ((Int.of_string s) : int) in if Int.( < ) i 0 || Int.( > ) i 255 then failwithf "%d is not a valid IPv4 octet (in %s)" i addr_s (); i) with | [a;b;c;d] -> let lower_24 = Int32.of_int_exn ((b lsl 16) lor (c lsl 8) lor d) and upper_8 = Int32.(shift_left (of_int_exn a) 24)in Int32.bit_or upper_8 lower_24 | _ -> failwithf "'%s' is not a valid IPv4 address" addr_s () (* Can we convert ip addr to an int? *) let test_inet4_addr_to_int32 str num = let inet = of_string str in Int32.( = ) (inet4_addr_to_int32_exn inet) num TEST = test_inet4_addr_to_int32 "0.0.0.1" 1l TEST = test_inet4_addr_to_int32 "1.0.0.0" 0x1000000l TEST = test_inet4_addr_to_int32 "255.255.255.255" 0xffffffffl TEST = test_inet4_addr_to_int32 "172.25.42.1" 0xac192a01l TEST = test_inet4_addr_to_int32 "4.2.2.1" 0x4020201l TEST = test_inet4_addr_to_int32 "8.8.8.8" 0x8080808l TEST = test_inet4_addr_to_int32 "173.194.73.103" 0xadc24967l TEST = test_inet4_addr_to_int32 "98.139.183.24" 0x628bb718l TEST = test_inet4_addr_to_int32 "0.0.0.0" 0l TEST = test_inet4_addr_to_int32 "127.0.0.1" 0x7F000001l TEST = test_inet4_addr_to_int32 "239.0.0.0" 0xEF000000l TEST = test_inet4_addr_to_int32 "255.255.255.255" 0xFFFFFFFFl (* And from an int to a string? *) let test_inet4_addr_of_int32 num str = let inet = of_string str in inet4_addr_of_int32 num = inet TEST = test_inet4_addr_of_int32 0xffffffffl "255.255.255.255" TEST = test_inet4_addr_of_int32 0l "0.0.0.0" TEST = test_inet4_addr_of_int32 0x628bb718l "98.139.183.24" TEST = test_inet4_addr_of_int32 0xadc24967l "173.194.73.103" (* And round trip for kicks *) TEST_UNIT = let inet = of_string "4.2.2.1" in let inet' = inet4_addr_of_int32 (inet4_addr_to_int32_exn inet) in if inet <> inet' then failwithf "round-tripping %s produced %s" (to_string inet) (to_string inet') () end (** IPv6 addresses are not supported. The RFC regarding how to properly format an IPv6 string is...painful. Note the 0010 and 0000: # "2a03:2880:0010:1f03:face:b00c:0000:0025" |! Unix.Inet_addr.of_string |! Unix.Inet_addr.to_string ;; - : string = "2a03:2880:10:1f03:face:b00c:0:25" *) module Cidr = struct module T0 = struct type t = { address : int32; (* IPv4 only *) bits : int; } with fields, bin_io, compare let create ~base_address ~bits = if bits < 0 || bits > 32 then failwithf "%d is an invalid number of mask bits (0 <= bits <= 32)" bits (); { address = Inet_addr.inet4_addr_to_int32_exn base_address; bits } let base_address t = Inet_addr.inet4_addr_of_int32 t.address let of_string s = match String.split ~on:'/' s with | [s_inet_address ; s_bits] -> create ~base_address:(Inet_addr.of_string s_inet_address) ~bits:(Int.of_string s_bits) | _ -> failwithf "Couldn't parse '%s' into a CIDR address/bits pair" s () let to_string t = let addr = Inet_addr.inet4_addr_of_int32 t.address in sprintf "%s/%d" (Inet_addr.to_string addr) t.bits let netmask_of_bits t = Int32.shift_left 0xffffffffl (32 - t.bits) |> Inet_addr.inet4_addr_of_int32 let start_address t = let baseip = t.address in let shift = 32 - t.bits in Int32.(shift_left (shift_right_logical baseip shift) shift) let does_match_int32 t address = Int32.equal (start_address t) (start_address {t with address}) let does_match t inet_addr = match Inet_addr.inet4_addr_to_int32_exn inet_addr with | exception _ -> false (* maybe they tried to use IPv6 *) | address -> does_match_int32 t address TEST = does_match (of_string "127.0.0.1/32") Inet_addr.localhost TEST = does_match (of_string "127.0.0.0/8") Inet_addr.localhost TEST = does_match (of_string "0.0.0.0/32") Inet_addr.bind_any TEST = does_match (of_string "0.0.0.0/0") Inet_addr.bind_any let multicast = of_string "224.0.0.0/4" TEST = does_match multicast (Inet_addr.of_string "224.0.0.1") TEST = does_match multicast (Inet_addr.of_string "239.0.0.1") TEST = not (does_match multicast (Inet_addr.of_string "240.0.0.1")) let all_matching_addresses t = Sequence.unfold ~init:(start_address t) ~f:(fun address -> if does_match_int32 t address then Some (Inet_addr.inet4_addr_of_int32 address, Int32.succ address) else None) TEST_MODULE = struct let match_strings c a = let c = of_string c in let a = Inet_addr.of_string a in does_match c a let is_multicast a = let a = Inet_addr.of_string a in does_match multicast a let of_string_ok s = try ignore (of_string s : t); true with _ -> false let of_string_err = Fn.compose not of_string_ok (* Can we parse some random correct netmasks? *) TEST = of_string_ok "10.0.0.0/8" TEST = of_string_ok "172.16.0.0/12" TEST = of_string_ok "192.168.0.0/16" TEST = of_string_ok "192.168.13.0/24" TEST = of_string_ok "172.25.42.0/18" (* Do we properly fail on some nonsense? *) TEST = of_string_err "172.25.42.0" TEST = of_string_err "172.25.42.0/35" TEST = of_string_err "172.25.42.0/sandwich" TEST = of_string_err "sandwich/sandwich" TEST = of_string_err "sandwich/39" TEST = of_string_err "sandwich/16" TEST = of_string_err "sandwich" TEST = of_string_err "172.52.43/16" TEST = of_string_err "172.52.493/16" (* Basic match tests *) TEST = match_strings "10.0.0.0/8" "9.255.255.255" = false TEST = match_strings "10.0.0.0/8" "10.0.0.1" = true TEST = match_strings "10.0.0.0/8" "10.34.67.1" = true TEST = match_strings "10.0.0.0/8" "10.255.255.255" = true TEST = match_strings "10.0.0.0/8" "11.0.0.1" = false TEST = match_strings "172.16.0.0/12" "172.15.255.255" = false TEST = match_strings "172.16.0.0/12" "172.16.0.0" = true TEST = match_strings "172.16.0.0/12" "172.31.255.254" = true TEST = match_strings "172.25.42.0/24" "172.25.42.1" = true TEST = match_strings "172.25.42.0/24" "172.25.42.255" = true TEST = match_strings "172.25.42.0/24" "172.25.42.0" = true TEST = match_strings "172.25.42.0/16" "172.25.0.1" = true TEST = match_strings "172.25.42.0/16" "172.25.255.254" = true TEST = match_strings "172.25.42.0/16" "172.25.42.1" = true TEST = match_strings "172.25.42.0/16" "172.25.105.237" = true (* And some that should fail *) TEST = match_strings "172.25.42.0/24" "172.26.42.47" = false TEST = match_strings "172.25.42.0/24" "172.26.42.208" = false (* Multicast tests *) TEST = is_multicast "224.0.0.0" = true TEST = is_multicast "224.0.0.1" = true TEST = is_multicast "239.255.255.255" = true TEST = is_multicast "240.0.0.0" = false TEST = is_multicast "223.0.0.1" = false TEST = is_multicast "226.128.255.16" = true TEST = is_multicast "233.128.255.16" = true TEST = is_multicast "155.246.1.20" = false TEST = is_multicast "0.0.0.0" = false TEST = is_multicast "127.0.0.1" = false let test_matching_addresses s l = <:test_result< Inet_addr.t list >> (of_string s |> all_matching_addresses |> Sequence.to_list) ~expect:(List.map l ~f:Inet_addr.of_string) TEST_UNIT = test_matching_addresses "172.16.0.8/32" [ "172.16.0.8" ] TEST_UNIT = test_matching_addresses "172.16.0.8/30" [ "172.16.0.8" ; "172.16.0.9" ; "172.16.0.10" ; "172.16.0.11" ] TEST_UNIT = test_matching_addresses "172.16.0.8/24" (List.init 256 ~f:(fun i -> sprintf "172.16.0.%d" i)) end end module T1 = struct include T0 (* Serialize to/of "a.b.c.d/x" instead of "((address abcd)(bits x))". *) include Sexpable.Of_stringable (T0) end include T1 include Comparable.Make_binable (T1) end module Protocol = struct type t = { name : string; aliases : string array; proto : int; } with sexp let of_unix u = { name = u.Unix.p_name; aliases = u.Unix.p_aliases; proto = u.Unix.p_proto; } exception Getbyname of string with sexp let (getbyname, getbyname_exn) = make_by (fun name -> of_unix (Unix.getprotobyname name)) (fun s -> Getbyname s) ;; exception Getbynumber of int with sexp let (getbynumber, getbynumber_exn) = make_by (fun i -> of_unix (Unix.getprotobynumber i)) (fun i -> Getbynumber i) ;; end module Service = struct type t = { name : string; aliases : string array; port : int; proto : string; } with sexp let of_unix u = { name = u.Unix.s_name; aliases = u.Unix.s_aliases; port = u.Unix.s_port; proto = u.Unix.s_proto; } exception Getbyname of string * string with sexp let getbyname_exn name ~protocol = try of_unix (Unix.getservbyname name ~protocol) with Not_found -> raise (Getbyname (name, protocol)) ;; let getbyname name ~protocol = try Some (of_unix (Unix.getservbyname name ~protocol)) with _ -> None ;; exception Getbyport of int * string with sexp let getbyport_exn num ~protocol = try of_unix (Unix.getservbyport num ~protocol) with Not_found -> raise (Getbyport (num, protocol)) ;; let getbyport num ~protocol = try Some (of_unix (Unix.getservbyport num ~protocol)) with Not_found -> None ;; end type socket_domain = Unix.socket_domain = | PF_UNIX | PF_INET | PF_INET6 with sexp, bin_io type socket_type = Unix.socket_type = | SOCK_STREAM | SOCK_DGRAM | SOCK_RAW | SOCK_SEQPACKET with sexp, bin_io type sockaddr = Unix.sockaddr = | ADDR_UNIX of string | ADDR_INET of Inet_addr.t * int with sexp, bin_io let domain_of_sockaddr = Unix.domain_of_sockaddr let addr_r addr = ("addr", sexp_of_sockaddr addr) let socket_or_pair f ~domain ~kind ~protocol = improve (fun () -> f ~domain ~kind ~protocol) (fun () -> [("domain", sexp_of_socket_domain domain); ("kind", sexp_of_socket_type kind); ("protocol", Int.sexp_of_t protocol)]) ;; let socket = socket_or_pair Unix.socket let socketpair = socket_or_pair Unix.socketpair let accept fd = let fd, addr = unary_fd Unix.accept fd in let addr = match addr with | ADDR_UNIX _ -> ADDR_UNIX "" | ADDR_INET _ -> addr in fd, addr let bind fd ~addr = improve (fun () -> Unix.bind fd ~addr) (fun () -> [fd_r fd; addr_r addr]) ;; let connect fd ~addr = improve (fun () -> Unix.connect fd ~addr) (fun () -> [fd_r fd; addr_r addr]) ;; let listen fd ~max = improve (fun () -> Unix.listen fd ~max) (fun () -> [fd_r fd; ("max", Int.sexp_of_t max)]) ;; type shutdown_command = Unix.shutdown_command = | SHUTDOWN_RECEIVE | SHUTDOWN_SEND | SHUTDOWN_ALL with sexp let shutdown fd ~mode = improve (fun () -> try Unix.shutdown fd ~mode with (* the error below is benign, it means that the other side disconnected *) | Unix.Unix_error (Unix.ENOTCONN, _, _) -> ()) (fun () -> [fd_r fd; ("mode", sexp_of_shutdown_command mode)]) ;; let getsockname = unary_fd Unix.getsockname let getpeername = unary_fd Unix.getpeername type msg_flag = Unix.msg_flag = | MSG_OOB | MSG_DONTROUTE | MSG_PEEK with sexp let recv_send f fd ~buf ~pos ~len ~mode = improve (fun () -> f fd ~buf ~pos ~len ~mode) (fun () -> [fd_r fd; ("pos", Int.sexp_of_t pos); len_r len; ("mode", sexp_of_list sexp_of_msg_flag mode)]) ;; let recv = recv_send Unix.recv let recvfrom = recv_send Unix.recvfrom let send = recv_send Unix.send let sendto fd ~buf ~pos ~len ~mode ~addr = improve (fun () -> Unix.sendto fd ~buf ~pos ~len ~mode ~addr) (fun () -> [fd_r fd; ("pos", Int.sexp_of_t pos); len_r len; ("mode", sexp_of_list sexp_of_msg_flag mode); ("addr", sexp_of_sockaddr addr)]) ;; type socket_bool_option = Unix.socket_bool_option = | SO_DEBUG | SO_BROADCAST | SO_REUSEADDR | SO_KEEPALIVE | SO_DONTROUTE | SO_OOBINLINE | SO_ACCEPTCONN | TCP_NODELAY | IPV6_ONLY with sexp type socket_int_option = Unix.socket_int_option = | SO_SNDBUF | SO_RCVBUF | SO_ERROR | SO_TYPE | SO_RCVLOWAT | SO_SNDLOWAT with sexp type socket_optint_option = Unix.socket_optint_option = | SO_LINGER with sexp type socket_float_option = Unix.socket_float_option = | SO_RCVTIMEO | SO_SNDTIMEO with sexp let make_sockopt get set sexp_of_opt sexp_of_val = let getsockopt fd opt = improve (fun () -> get fd opt) (fun () -> [fd_r fd; ("opt", sexp_of_opt opt)]) in let setsockopt fd opt value = improve (fun () -> set fd opt value) (fun () -> [fd_r fd; ("opt", sexp_of_opt opt); ("val", sexp_of_val value)]) in (getsockopt, setsockopt) ;; let (getsockopt, setsockopt) = make_sockopt Unix.getsockopt Unix.setsockopt sexp_of_socket_bool_option sexp_of_bool ;; let (getsockopt_int, setsockopt_int) = make_sockopt Unix.getsockopt_int Unix.setsockopt_int sexp_of_socket_int_option sexp_of_int ;; let (getsockopt_optint, setsockopt_optint) = make_sockopt Unix.getsockopt_optint Unix.setsockopt_optint sexp_of_socket_optint_option (sexp_of_option sexp_of_int) ;; let (getsockopt_float, setsockopt_float) = make_sockopt Unix.getsockopt_float Unix.setsockopt_float sexp_of_socket_float_option sexp_of_float ;; (* Additional IP functionality *) external if_indextoname : int -> string = "unix_if_indextoname" module Mcast_action = struct (* Keep this in sync with the VAL_MCAST_ACTION_* #defines in unix_stubs.c *) type t = | Add | Drop end external mcast_modify : Mcast_action.t -> ?ifname : string -> ?source : Inet_addr.t -> File_descr.t -> Unix.sockaddr -> unit = "core_unix_mcast_modify" ;; let mcast_join ?ifname ?source fd sockaddr = mcast_modify Mcast_action.Add ?ifname ?source fd sockaddr ;; let mcast_leave ?ifname fd sockaddr = mcast_modify Mcast_action.Drop ?ifname fd sockaddr ;; external get_mcast_ttl : File_descr.t -> int = "unix_mcast_get_ttl" external set_mcast_ttl : File_descr.t -> int -> unit = "unix_mcast_set_ttl" external get_mcast_loop : File_descr.t -> bool = "unix_mcast_get_loop" external set_mcast_loop : File_descr.t -> bool -> unit = "unix_mcast_set_loop" external set_mcast_ifname : File_descr.t -> string -> unit = "unix_mcast_set_ifname" let open_connection addr = improve (fun () -> Unix.open_connection addr) (fun () -> [addr_r addr]) ;; let shutdown_connection = Unix.shutdown_connection let establish_server handle_connection ~addr = improve (fun () -> Unix.establish_server handle_connection ~addr) (fun () -> [addr_r addr]) ;; type addr_info = Unix.addr_info = { ai_family : socket_domain; ai_socktype : socket_type; ai_protocol : int; ai_addr : sockaddr; ai_canonname : string; } with sexp type getaddrinfo_option = Unix.getaddrinfo_option = | AI_FAMILY of socket_domain | AI_SOCKTYPE of socket_type | AI_PROTOCOL of int | AI_NUMERICHOST | AI_CANONNAME | AI_PASSIVE with sexp let getaddrinfo host service opts = improve (fun () -> Unix.getaddrinfo host service opts) (fun () -> [("host", atom host); ("service", atom service); ("opts", sexp_of_list sexp_of_getaddrinfo_option opts)]) ;; type name_info = Unix.name_info = { ni_hostname : string; ni_service : string; } with sexp type getnameinfo_option = Unix.getnameinfo_option = | NI_NOFQDN | NI_NUMERICHOST | NI_NAMEREQD | NI_NUMERICSERV | NI_DGRAM with sexp let getnameinfo addr opts = improve (fun () -> Unix.getnameinfo addr opts) (fun () -> [("addr", sexp_of_sockaddr addr); ("opts", sexp_of_list sexp_of_getnameinfo_option opts)]) ;; module Terminal_io = struct type t = Unix.terminal_io = { mutable c_ignbrk : bool; mutable c_brkint : bool; mutable c_ignpar : bool; mutable c_parmrk : bool; mutable c_inpck : bool; mutable c_istrip : bool; mutable c_inlcr : bool; mutable c_igncr : bool; mutable c_icrnl : bool; mutable c_ixon : bool; mutable c_ixoff : bool; mutable c_opost : bool; mutable c_obaud : int; mutable c_ibaud : int; mutable c_csize : int; mutable c_cstopb : int; mutable c_cread : bool; mutable c_parenb : bool; mutable c_parodd : bool; mutable c_hupcl : bool; mutable c_clocal : bool; mutable c_isig : bool; mutable c_icanon : bool; mutable c_noflsh : bool; mutable c_echo : bool; mutable c_echoe : bool; mutable c_echok : bool; mutable c_echonl : bool; mutable c_vintr : char; mutable c_vquit : char; mutable c_verase : char; mutable c_vkill : char; mutable c_veof : char; mutable c_veol : char; mutable c_vmin : int; mutable c_vtime : int; mutable c_vstart : char; mutable c_vstop : char; } with sexp let tcgetattr = unary_fd Unix.tcgetattr type setattr_when = Unix.setattr_when = | TCSANOW | TCSADRAIN | TCSAFLUSH with sexp let tcsetattr t fd ~mode = improve (fun () -> Unix.tcsetattr fd ~mode t) (fun () -> [fd_r fd; ("mode", sexp_of_setattr_when mode); ("termios", sexp_of_t t)]) ;; let tcsendbreak fd ~duration = improve (fun () -> Unix.tcsendbreak fd ~duration) (fun () -> [fd_r fd; ("duration", Int.sexp_of_t duration)]) ;; let tcdrain = unary_fd Unix.tcdrain type flush_queue = Unix.flush_queue = | TCIFLUSH | TCOFLUSH | TCIOFLUSH with sexp let tcflush fd ~mode = improve (fun () -> Unix.tcflush fd ~mode) (fun () -> [fd_r fd; ("mode", sexp_of_flush_queue mode)]) ;; type flow_action = Unix.flow_action = | TCOOFF | TCOON | TCIOFF | TCION with sexp let tcflow fd ~mode = improve (fun () -> Unix.tcflow fd ~mode) (fun () -> [fd_r fd; ("mode", sexp_of_flow_action mode)]) ;; let setsid = Unix.setsid end let get_sockaddr name port = ADDR_INET (Inet_addr.of_string_or_getbyname name, port) let set_in_channel_timeout ic rcv_timeout = let s = descr_of_in_channel ic in setsockopt_float s SO_RCVTIMEO rcv_timeout let set_out_channel_timeout oc snd_timeout = let s = descr_of_out_channel oc in setsockopt_float s SO_SNDTIMEO snd_timeout external nanosleep : float -> float = "core_time_ns_nanosleep" ;; module Syslog = Syslog let () = Sexplib_unix.Sexplib_unix_conv.linkme (* Test the Sexplib_unix exn converter was added correctly *) TEST_UNIT "Sexplib_unix sexp converter" = let open Sexp.O in match sexp_of_exn (Unix.Unix_error (E2BIG, "loc", "arg")) with | (List [ Atom "Unix.Unix_error" ; Atom _human_readable_message ; Atom "loc" ; Atom "arg" ]) -> () | something_else -> failwithf "sexp_of_exn (Unix_error ...) gave %s" (Sexp.to_string something_else) () ;; core-113.00.00/src/core_unix.mli000066400000000000000000002323251256461075500162530ustar00rootroot00000000000000(* This file is a modified version of unixLabels.mli from the OCaml distribution. *) INCLUDE "core_config.mlh" open Core_kernel.Std (** File descriptor. *) module File_descr : sig type t = Unix.file_descr with bin_io, sexp include Equal .S with type t := t include Hashable .S with type t := t include Stringable.S with type t := t val of_int : int -> t val to_int : t -> int end (** {6 Error report} *) (** The type of error codes. Errors defined in the POSIX standard and additional errors, mostly BSD. All other errors are mapped to [EUNKNOWNERR]. @deprecated in favor of {!Error.t} below. *) type error = Unix.error = E2BIG (** Argument list too long *) | EACCES (** Permission denied *) | EAGAIN (** Resource temporarily unavailable; try again *) | EBADF (** Bad file descriptor *) | EBUSY (** Resource unavailable *) | ECHILD (** No child process *) | EDEADLK (** Resource deadlock would occur *) | EDOM (** Domain error for math functions, etc. *) | EEXIST (** File exists *) | EFAULT (** Bad address *) | EFBIG (** File too large *) | EINTR (** Function interrupted by signal *) | EINVAL (** Invalid argument *) | EIO (** Hardware I/O error *) | EISDIR (** Is a directory *) | EMFILE (** Too many open files by the process *) | EMLINK (** Too many links *) | ENAMETOOLONG (** Filename too long *) | ENFILE (** Too many open files in the system *) | ENODEV (** No such device *) | ENOENT (** No such file or directory *) | ENOEXEC (** Not an executable file *) | ENOLCK (** No locks available *) | ENOMEM (** Not enough memory *) | ENOSPC (** No space left on device *) | ENOSYS (** Function not supported *) | ENOTDIR (** Not a directory *) | ENOTEMPTY (** Directory not empty *) | ENOTTY (** Inappropriate I/O control operation *) | ENXIO (** No such device or address *) | EPERM (** Operation not permitted *) | EPIPE (** Broken pipe *) | ERANGE (** Result too large *) | EROFS (** Read-only file system *) | ESPIPE (** Invalid seek e.g. on a pipe *) | ESRCH (** No such process *) | EXDEV (** Invalid link *) | EWOULDBLOCK (** Operation would block *) | EINPROGRESS (** Operation now in progress *) | EALREADY (** Operation already in progress *) | ENOTSOCK (** Socket operation on non-socket *) | EDESTADDRREQ (** Destination address required *) | EMSGSIZE (** Message too long *) | EPROTOTYPE (** Protocol wrong type for socket *) | ENOPROTOOPT (** Protocol not available *) | EPROTONOSUPPORT (** Protocol not supported *) | ESOCKTNOSUPPORT (** Socket type not supported *) | EOPNOTSUPP (** Operation not supported on socket *) | EPFNOSUPPORT (** Protocol family not supported *) | EAFNOSUPPORT (** Address family not supported by protocol family *) | EADDRINUSE (** Address already in use *) | EADDRNOTAVAIL (** Can't assign requested address *) | ENETDOWN (** Network is down *) | ENETUNREACH (** Network is unreachable *) | ENETRESET (** Network dropped connection on reset *) | ECONNABORTED (** Software caused connection abort *) | ECONNRESET (** Connection reset by peer *) | ENOBUFS (** No buffer space available *) | EISCONN (** Socket is already connected *) | ENOTCONN (** Socket is not connected *) | ESHUTDOWN (** Can't send after socket shutdown *) | ETOOMANYREFS (** Too many references: can't splice *) | ETIMEDOUT (** Connection timed out *) | ECONNREFUSED (** Connection refused *) | EHOSTDOWN (** Host is down *) | EHOSTUNREACH (** No route to host *) | ELOOP (** Too many levels of symbolic links *) | EOVERFLOW (** File size or position not representable *) | EUNKNOWNERR of int (** Unknown error *) with sexp module Error : sig (** The type of error codes. Errors defined in the POSIX standard and additional errors, mostly BSD. All other errors are mapped to [EUNKNOWNERR]. *) type t = Unix.error = | E2BIG (** Argument list too long *) | EACCES (** Permission denied *) | EAGAIN (** Resource temporarily unavailable; try again *) | EBADF (** Bad file descriptor *) | EBUSY (** Resource unavailable *) | ECHILD (** No child process *) | EDEADLK (** Resource deadlock would occur *) | EDOM (** Domain error for math functions, etc. *) | EEXIST (** File exists *) | EFAULT (** Bad address *) | EFBIG (** File too large *) | EINTR (** Function interrupted by signal *) | EINVAL (** Invalid argument *) | EIO (** Hardware I/O error *) | EISDIR (** Is a directory *) | EMFILE (** Too many open files by the process *) | EMLINK (** Too many links *) | ENAMETOOLONG (** Filename too long *) | ENFILE (** Too many open files in the system *) | ENODEV (** No such device *) | ENOENT (** No such file or directory *) | ENOEXEC (** Not an executable file *) | ENOLCK (** No locks available *) | ENOMEM (** Not enough memory *) | ENOSPC (** No space left on device *) | ENOSYS (** Function not supported *) | ENOTDIR (** Not a directory *) | ENOTEMPTY (** Directory not empty *) | ENOTTY (** Inappropriate I/O control operation *) | ENXIO (** No such device or address *) | EPERM (** Operation not permitted *) | EPIPE (** Broken pipe *) | ERANGE (** Result too large *) | EROFS (** Read-only file system *) | ESPIPE (** Invalid seek e.g. on a pipe *) | ESRCH (** No such process *) | EXDEV (** Invalid link *) | EWOULDBLOCK (** Operation would block *) | EINPROGRESS (** Operation now in progress *) | EALREADY (** Operation already in progress *) | ENOTSOCK (** Socket operation on non-socket *) | EDESTADDRREQ (** Destination address required *) | EMSGSIZE (** Message too long *) | EPROTOTYPE (** Protocol wrong type for socket *) | ENOPROTOOPT (** Protocol not available *) | EPROTONOSUPPORT (** Protocol not supported *) | ESOCKTNOSUPPORT (** Socket type not supported *) | EOPNOTSUPP (** Operation not supported on socket *) | EPFNOSUPPORT (** Protocol family not supported *) | EAFNOSUPPORT (** Address family not supported by protocol family *) | EADDRINUSE (** Address already in use *) | EADDRNOTAVAIL (** Can't assign requested address *) | ENETDOWN (** Network is down *) | ENETUNREACH (** Network is unreachable *) | ENETRESET (** Network dropped connection on reset *) | ECONNABORTED (** Software caused connection abort *) | ECONNRESET (** Connection reset by peer *) | ENOBUFS (** No buffer space available *) | EISCONN (** Socket is already connected *) | ENOTCONN (** Socket is not connected *) | ESHUTDOWN (** Can't send after socket shutdown *) | ETOOMANYREFS (** Too many references: can't splice *) | ETIMEDOUT (** Connection timed out *) | ECONNREFUSED (** Connection refused *) | EHOSTDOWN (** Host is down *) | EHOSTUNREACH (** No route to host *) | ELOOP (** Too many levels of symbolic links *) | EOVERFLOW (** File size or position not representable *) | EUNKNOWNERR of int (** Unknown error *) with sexp val of_system_int : errno:int -> t (** Return a string describing the given error code. *) val message : t -> string end (** Raised by the system calls below when an error is encountered. The first component is the error code; the second component is the function name; the third component is the string parameter to the function, if it has one, or the empty string otherwise. *) exception Unix_error of Error.t * string * string module Syscall_result : module type of Syscall_result with type 'a t = 'a Syscall_result.t (** @raise Unix_error with a given errno, function name and argument *) external unix_error : int -> string -> string -> _ = "unix_error_stub" (** Return a string describing the given error code. @deprecated in favor of {!Error.message}. *) val error_message : error -> string (** [handle_unix_error f] runs [f ()] and returns the result. If the exception [Unix_error] is raised, it prints a message describing the error and exits with code 2. *) val handle_unix_error : (unit -> 'a) -> 'a (** [retry_until_no_eintr f] returns [f ()] unless [f ()] fails with [EINTR]; in which case [f ()] is run again until it raises a different error or returns a value. *) val retry_until_no_eintr : (unit -> 'a) -> 'a (** {6 Access to the process environment} If you're looking for [getenv], that's in the Sys module. *) (** Return the process environment, as an array of strings with the format ``variable=value''. *) val environment : unit -> string array (** [Unix.putenv ~key ~data] sets the value associated to a variable in the process environment. [key] is the name of the environment variable, and [data] its new associated value. *) val putenv : key : string -> data : string -> unit (** [unsetenv name] deletes the variable [name] from the environment. EINVAL [name] contained an ’=’ or an '\000' character. *) val unsetenv : string -> unit (** {6 Process handling} *) (** The termination status of a process. *) module Exit : sig type error = [ `Exit_non_zero of int ] with compare, sexp type t = (unit, error) Result.t with compare, sexp val to_string_hum : t -> string val code : t -> int val of_code : int -> t val or_error : t -> unit Or_error.t end module Exit_or_signal : sig type error = [ Exit.error | `Signal of Signal.t ] with compare, sexp type t = (unit, error) Result.t with compare, sexp (** [of_unix] assumes that any signal numbers in the incoming value are O'Caml internal signal numbers. *) val of_unix : Unix.process_status -> t val to_string_hum : t -> string val or_error : t -> unit Or_error.t end module Exit_or_signal_or_stop : sig type error = [ Exit_or_signal.error | `Stop of Signal.t ] with sexp type t = (unit, error) Result.t with sexp (** [of_unix] assumes that any signal numbers in the incoming value are O'Caml internal signal numbers. *) val of_unix : Unix.process_status -> t val to_string_hum : t -> string val or_error : t -> unit Or_error.t end (** [env] is used to control the environment of a child process, and can take three forms. [`Replace_raw] replaces the entire environment with strings in the Unix style, like ["VARIABLE_NAME=value"]. [`Replace] has the same effect as [`Replace_raw], but using bindings represented as ["VARIABLE_NAME", "value"]. [`Extend] adds entries to the existing environment rather than replacing the whole environment. If [env] contains multiple bindings for the same variable, the last takes precedence. In the case of [`Extend], bindings in [env] take precedence over the existing environment. *) type env = [ `Replace of (string * string) list | `Extend of (string * string) list | `Replace_raw of string list ] with sexp (** [exec ~prog ~args ?search_path ?env] execs [prog] with [args]. If [use_path = true] (the default) and [prog] doesn't contain a slash, then [exec] searches the [PATH] environment variable for [prog]. If [env] is supplied, it determines the environment when [prog] is executed. The first element in args should be the program itself; the correct way to call [exec] is: {[ exec ~prog ~args:[ prog; arg1; arg2; ...] () ]} *) val exec : prog:string -> args:string list -> ?use_path:bool (** default is [true] *) -> ?env:env -> unit -> never_returns (** [fork_exec ~prog ~args ?use_path ?env ()] forks and execs [prog] with [args] in the child process, returning the child PID to the parent. *) val fork_exec : prog:string -> args:string list -> ?use_path:bool (** default is [true] *) -> ?env:env -> unit -> Pid.t (** [fork ()] forks a new process. The return value indicates whether we are continuing in the child or the parent, and if the parent, includes the child's process id. *) val fork : unit -> [ `In_the_child | `In_the_parent of Pid.t ] (** [wait{,_nohang,_untraced,_nohang_untraced} ?restart wait_on] is a family of functions that wait on a process to exit (normally or via a signal) or be stopped by a signal (if [untraced] is used). The [wait_on] argument specifies which processes to wait on. The [nohang] variants return [None] immediately if no such process exists. If [nohang] is not used, [waitpid] will block until one of the desired processes exits. The non-nohang variants have a [restart] flag with (default true) that causes the system call to be retried upon EAGAIN|EINTR. The nohang variants do not have this flag because they don't block. *) type wait_on = [ `Any | `Group of Pid.t | `My_group | `Pid of Pid.t ] with sexp val wait : ?restart:bool (* defaults to true *) -> wait_on -> Pid.t * Exit_or_signal.t val wait_nohang : wait_on -> (Pid.t * Exit_or_signal .t ) option val wait_untraced : ?restart:bool (* defaults to true *) -> wait_on -> Pid.t * Exit_or_signal_or_stop.t val wait_nohang_untraced : wait_on -> (Pid.t * Exit_or_signal_or_stop.t) option (** [waitpid pid] waits for child process [pid] to terminate, and returns its exit status. [waitpid_exn] is like [waitpid], except it only returns if the child exits with status zero, and raises if the child terminates in any other way. *) val waitpid : Pid.t -> Exit_or_signal.t val waitpid_exn : Pid.t -> unit (** Execute the given command, wait until it terminates, and return its termination status. The string is interpreted by the shell [/bin/sh] and therefore can contain redirections, quotes, variables, etc. The result [WEXITED 127] indicates that the shell couldn't be executed. *) val system : string -> Exit_or_signal.t (** Return the pid of the process. *) val getpid : unit -> Pid.t (** Return the pid of the parent process. *) val getppid : unit -> Pid.t option (** Return the pid of the parent process, if you're really sure you're never going to be the init process. *) val getppid_exn : unit -> Pid.t module Thread_id : sig type t with sexp_of, bin_io include Comparable.S with type t := t val to_int : t -> int end (** Get the numeric ID of the current thread, e.g. for identifying it in top(1). *) val gettid : (unit -> Thread_id.t) Or_error.t (** Change the process priority. The integer argument is added to the ``nice'' value. (Higher values of the ``nice'' value mean lower priorities.) Return the new nice value. *) val nice : int -> int (** {6 Basic file input/output} *) (** The abstract type of file descriptors. *) (** File descriptor for standard input.*) val stdin : File_descr.t (** File descriptor for standard output.*) val stdout : File_descr.t (** File descriptor for standard standard error. *) val stderr : File_descr.t (** The flags to {!UnixLabels.openfile}. *) type open_flag = Unix.open_flag = O_RDONLY (** Open for reading *) | O_WRONLY (** Open for writing *) | O_RDWR (** Open for reading and writing *) | O_NONBLOCK (** Open in non-blocking mode *) | O_APPEND (** Open for append *) | O_CREAT (** Create if nonexistent *) | O_TRUNC (** Truncate to 0 length if existing *) | O_EXCL (** Fail if existing *) | O_NOCTTY (** Don't make this dev a controlling tty *) | O_DSYNC (** Writes complete as `Synchronised I/O data integrity completion' *) | O_SYNC (** Writes complete as `Synchronised I/O file integrity completion' *) | O_RSYNC (** Reads complete as writes (depending on O_SYNC/O_DSYNC) *) | O_SHARE_DELETE (** Windows only: allow the file to be deleted while still open *) | O_CLOEXEC (** Set the close-on-exec flag on the descriptor returned by {!openfile} *) (* We can't use [with sexp] because pa_sexp inserts two copies of the [val] specs, which leads to a spurious "unused" warning. *) val open_flag_of_sexp : Sexp.t -> open_flag val sexp_of_open_flag : open_flag -> Sexp.t (** The type of file access rights. *) type file_perm = int with sexp (** Open the named file with the given flags. Third argument is the permissions to give to the file if it is created. Return a file descriptor on the named file. Default permissions 0o644. *) val openfile : ?perm:file_perm -> mode:open_flag list -> string -> File_descr.t module Open_flags : sig (** [Open_flags.t] represents the flags associated with a file descriptor in the open-file-descriptor table. It deals with the same thing as OCaml's [open_flag] type; however, it uses Core's [Flags] approach and the underlying integer bitmask representation, and so interoperates more smoothly with C. *) type t with sexp_of include Flags.S with type t := t (** access mode. These three flags are not individual bits like flags usually are. The access mode is represented by the lower two bits of the [Open_flags.t]. A particular [Open_flags.t] should include exactly one access mode. Combining different [Open_flags.t]'s using flags operations (e.g [+]) is only sensible if they have the same access mode. *) val rdonly : t val wronly : t val rdwr : t (** creation *) val creat : t val excl : t val noctty : t val trunc : t val append : t val nonblock : t val dsync : t val sync : t val rsync : t (** [can_read t] iff [t] has [rdonly] or [rdwr] *) val can_read : t -> bool (** [can_read t] iff [t] has [wronly] or [rdwr] *) val can_write : t -> bool end (** [fcntl_getfl fd] gets the current flags for [fd] from the open-file-descriptor table via the system call [fcntl(fd, F_GETFL)]. See "man fcntl". *) val fcntl_getfl : File_descr.t -> Open_flags.t (** [fcntl_setfl fd flags] sets the flags for [fd] in the open-file-descriptor table via the system call [fcntl(fd, F_SETFL, flags)]. See "man fcntl". As per the Linux man page, on Linux this only allows [append] and [nonblock] to be set. *) val fcntl_setfl : File_descr.t -> Open_flags.t -> unit (** Close a file descriptor. *) val close : ?restart:bool (* defaults to false *) -> File_descr.t -> unit (** [with_file file ~mode ~perm ~f] opens [file], and applies [f] to the resulting file descriptor. When [f] finishes (or raises), [with_file] closes the descriptor and returns the result of [f] (or raises). *) val with_file : ?perm:file_perm -> string -> mode:open_flag list -> f:(File_descr.t -> 'a) -> 'a (** [read fd buff ofs len] reads [len] characters from descriptor [fd], storing them in string [buff], starting at position [ofs] in string [buff]. Return the number of characters actually read. *) val read : ?restart:bool (* defaults to false *) -> ?pos:int -> ?len:int -> File_descr.t -> buf:string -> int (** [write fd buff ofs len] writes [len] characters to descriptor [fd], taking them from string [buff], starting at position [ofs] in string [buff]. Return the number of characters actually written. When an error is reported some characters might have already been written. Use [single_write] instead to ensure that this is not the case. WARNING: write is an interruptible call and has no way to handle EINTR properly. You should most probably be using single write. *) val write : ?pos:int -> ?len:int -> File_descr.t -> buf:string -> int (** Same as [write] but ensures that all errors are reported and that no character has ever been written when an error is reported. *) val single_write : ?restart:bool (* defaults to false *) -> ?pos:int -> ?len:int -> File_descr.t -> buf:string -> int (** {6 Interfacing with the standard input/output library} *) (** Create an input channel reading from the given descriptor. The channel is initially in binary mode; use [set_binary_mode_in ic false] if text mode is desired. *) val in_channel_of_descr : File_descr.t -> In_channel.t (** Create an output channel writing on the given descriptor. The channel is initially in binary mode; use [set_binary_mode_out oc false] if text mode is desired. *) val out_channel_of_descr : File_descr.t -> Out_channel.t (** Return the descriptor corresponding to an input channel. *) val descr_of_in_channel : In_channel.t -> File_descr.t (** Return the descriptor corresponding to an output channel. *) val descr_of_out_channel : Out_channel.t -> File_descr.t (** {6 Seeking and truncating} *) (** POSITIONING modes for {!UnixLabels.lseek}. *) type seek_command = Unix.seek_command = SEEK_SET (** indicates positions relative to the beginning of the file *) | SEEK_CUR (** indicates positions relative to the current position *) | SEEK_END (** indicates positions relative to the end of the file *) with sexp (** Set the current position for a file descriptor *) val lseek : File_descr.t -> int64 -> mode:seek_command -> int64 (** Truncates the named file to the given size. *) val truncate : string -> len:int64 -> unit (** Truncates the file corresponding to the given descriptor to the given size. *) val ftruncate : File_descr.t -> len:int64 -> unit (** {6 File statistics} *) type file_kind = Unix.file_kind = S_REG (** Regular file *) | S_DIR (** Directory *) | S_CHR (** Character device *) | S_BLK (** Block device *) | S_LNK (** Symbolic link *) | S_FIFO (** Named pipe *) | S_SOCK (** Socket *) with sexp (** The informations returned by the {!UnixLabels.stat} calls. *) type stats = Unix.LargeFile.stats = { st_dev : int; (** Device number *) st_ino : int; (** Inode number *) st_kind : file_kind; (** Kind of the file *) st_perm : file_perm; (** Access rights *) st_nlink : int; (** Number of links *) st_uid : int; (** User id of the owner *) st_gid : int; (** Group ID of the file's group *) st_rdev : int; (** Device minor number *) st_size : int64; (** Size in bytes *) (* The floats below are really Time.t or Time.Span.t, but Time depends on Unix, so the fix isn't so trivial. Same for Native_file.stats below. *) st_atime : float; (** Last access time *) st_mtime : float; (** Last modification time *) st_ctime : float (** Last status change time *) } with sexp (** Return the information for the named file. *) val stat : string -> stats (** Same as {!UnixLabels.stat}, but in case the file is a symbolic link, return the information for the link itself. *) val lstat : string -> stats (** Return the information for the file associated with the given descriptor. *) val fstat : File_descr.t -> stats (* This sub-module provides the normal OCaml Unix functions that deal with file size using native ints. These are here because, in general, you should be using 64bit file operations so that large files aren't an issue. If you have a real need to use potentially 31bit file operations (and you should be dubious of such a need) you can open this module *) module Native_file : sig (** The informations returned by the {!UnixLabels.stat} calls. *) type stats = Unix.stats = { st_dev : int; (** Device number *) st_ino : int; (** Inode number *) st_kind : file_kind; (** Kind of the file *) st_perm : file_perm; (** Access rights *) st_nlink : int; (** Number of links *) st_uid : int; (** User id of the owner *) st_gid : int; (** Group ID of the file's group *) st_rdev : int; (** Device minor number *) st_size : int; (** Size in bytes *) st_atime : float; (** Last access time *) st_mtime : float; (** Last modification time *) st_ctime : float (** Last status change time *) } with sexp (** Return the information for the named file. *) val stat : string -> stats (** Same as {!UnixLabels.stat}, but in case the file is a symbolic link, return the information for the link itself. *) val lstat : string -> stats (** Return the information for the file associated with the given descriptor. *) val fstat : File_descr.t -> stats val lseek : File_descr.t -> int -> mode:seek_command -> int val truncate : string -> len:int -> unit val ftruncate : File_descr.t -> len:int -> unit end (** {6 Locking} *) (** Commands for {!lockf}. *) type lock_command = Unix.lock_command = F_ULOCK (** Unlock a region *) | F_LOCK (** Lock a region for writing, and block if already locked *) | F_TLOCK (** Lock a region for writing, or fail if already locked *) | F_TEST (** Test a region for other process locks *) | F_RLOCK (** Lock a region for reading, and block if already locked *) | F_TRLOCK (** Lock a region for reading, or fail if already locked *) with sexp (** [lockf fd cmd size] place a lock on a file_descr that prevents any other process from * calling lockf successfully on the same file. Due to a limitation in the current * implementation the length will be converted to a native int, potentially throwing an * exception if it is too large. *) val lockf : File_descr.t -> mode:lock_command -> len:Int64.t -> unit module Flock_command : sig type t val lock_shared : t val lock_exclusive : t val unlock : t end (** [flock fd cmd] places or releases a lock on the fd as per the flock C call of the same name. *) val flock : File_descr.t -> Flock_command.t -> bool (** Return [true] if the given file descriptor refers to a terminal or console window, [false] otherwise. *) val isatty : File_descr.t -> bool (* {6 Seeking, truncating and statistics on large files} *) (** {6 Operations on file names} *) (** Removes the named file *) val unlink : string -> unit (** Removes the named file or directory *) val remove : string -> unit (** [rename old new] changes the name of a file from [old] to [new]. *) val rename : src:string -> dst:string -> unit (** [link ?force ~target ~link_name ()] creates a hard link named [link_name] to the file named [target]. If [force] is true, an existing entry in place of [link_name] will be unlinked. This unlinking may raise a Unix error, e.g. if the entry is a directory. *) val link : ?force:bool (* defaults to false *) -> target : string -> link_name : string -> unit -> unit (** {6 File permissions and ownership} *) (** Change the permissions of the named file. *) val chmod : string -> perm:file_perm -> unit (** Change the permissions of an opened file. *) val fchmod : File_descr.t -> perm:file_perm -> unit (** Change the owner uid and owner gid of the named file. *) val chown : string -> uid:int -> gid:int -> unit (** Change the owner uid and owner gid of an opened file. *) val fchown : File_descr.t -> uid:int -> gid:int -> unit (** Set the process creation mask, and return the previous mask. *) val umask : int -> int (** Check that the process has the given permissions over the named file. *) val access : string -> [ `Read | `Write | `Exec | `Exists ] list -> (unit, exn) Result.t val access_exn : string -> [ `Read | `Write | `Exec | `Exists ] list -> unit (** {6 Operations on file descriptors} *) (** Return a new file descriptor referencing the same file as the given descriptor. *) val dup : File_descr.t -> File_descr.t (** [dup2 ~src ~dst] duplicates [src] to [dst], closing [dst] if already opened. *) val dup2 : src:File_descr.t -> dst:File_descr.t -> unit (** Set the ``non-blocking'' flag on the given descriptor. When the non-blocking flag is set, reading on a descriptor on which there is temporarily no data available raises the [EAGAIN] or [EWOULDBLOCK] error instead of blocking; writing on a descriptor on which there is temporarily no room for writing also raises [EAGAIN] or [EWOULDBLOCK]. *) val set_nonblock : File_descr.t -> unit (** Clear the ``non-blocking'' flag on the given descriptor. See {!UnixLabels.set_nonblock}.*) val clear_nonblock : File_descr.t -> unit (** Set the ``close-on-exec'' flag on the given descriptor. A descriptor with the close-on-exec flag is automatically closed when the current process starts another program with one of the [exec] functions. *) val set_close_on_exec : File_descr.t -> unit (** Clear the ``close-on-exec'' flag on the given descriptor. See {!UnixLabels.set_close_on_exec}.*) val clear_close_on_exec : File_descr.t -> unit (** {6 Directories} *) (** Create a directory. The permissions of the created directory are (perm & ~umask & 0777). The default perm is 0777. *) val mkdir : ?perm:file_perm -> string -> unit (** Create a directory recursively. The permissions of the created directory are those granted by [mkdir ~perm]. *) val mkdir_p : ?perm:file_perm -> string -> unit (** Remove an empty directory. *) val rmdir : string -> unit (** Change the process working directory. *) val chdir : string -> unit (** Return the name of the current working directory. *) val getcwd : unit -> string (** Change the process root directory. *) val chroot : string -> unit (** The type of descriptors over opened directories. *) type dir_handle = Unix.dir_handle (** Open a descriptor on a directory *) val opendir : ?restart:bool (* defaults to false *) -> string -> dir_handle (** Return the next entry in a directory. @raise End_of_file when the end of the directory has been reached. *) val readdir : dir_handle -> string (** Reposition the descriptor to the beginning of the directory *) val rewinddir : dir_handle -> unit (** Close a directory descriptor. *) val closedir : dir_handle -> unit (** {6 Pipes and redirections} *) (** Create a pipe. The first component of the result is opened for reading, that's the exit to the pipe. The second component is opened for writing, that's the entrance to the pipe. *) val pipe : unit -> File_descr.t * File_descr.t (** Create a named pipe with the given permissions. *) val mkfifo : string -> perm:file_perm -> unit (** {6 High-level process and redirection management} *) module Process_info : sig type t = { pid: Pid.t; stdin: File_descr.t; stdout: File_descr.t; stderr: File_descr.t } with sexp end (** Low-level process *) (** [create_process ~prog ~args] forks a new process that executes the program [prog] with arguments [args]. The function returns the pid of the process along with file descriptors attached to stdin, stdout, and stderr of the new process. The executable file [prog] is searched for in the path. The new process has the same environment as the current process. Unlike in [execve] the program name is automatically passed as the first argument. *) val create_process : prog : string -> args : string list -> Process_info.t (** [create_process_env ~prog ~args ~env] as [create_process], but takes an additional parameter that extends or replaces the current environment. No effort is made to ensure that the keys passed in as env are unique, so if an environment variable is set twice the second version will override the first. *) val create_process_env : ?working_dir : string -> prog : string -> args : string list -> env : env -> unit -> Process_info.t (** High-level pipe and process management. These functions (with {!UnixLabels.open_process_out} and {!UnixLabels.open_process}) run the given command in parallel with the program, and return channels connected to the standard input and/or the standard output of the command. The command is interpreted by the shell [/bin/sh] (cf. [system]). Warning: writes on channels are buffered, hence be careful to call {!Pervasives.flush} at the right times to ensure correct synchronization. *) val open_process_in : string -> in_channel (** See {!UnixLabels.open_process_in}. *) val open_process_out : string -> out_channel (** See {!UnixLabels.open_process_in}. *) val open_process : string -> in_channel * out_channel (** Similar to {!UnixLabels.open_process}, but the second argument specifies the environment passed to the command. The result is a triple of channels connected to the standard output, standard input, and standard error of the command. *) module Process_channels : sig type t = { stdin : out_channel; stdout : in_channel; stderr : in_channel; } end val open_process_full : string -> env:string array -> Process_channels.t (* close_process_* raises Unix_error if, for example, the file descriptor has already been closed. *) (** Close channels opened by {!UnixLabels.open_process_in}, wait for the associated command to terminate, and return its termination status. *) val close_process_in : in_channel -> Exit_or_signal.t (** Close channels opened by {!UnixLabels.open_process_out}, wait for the associated command to terminate, and return its termination status. *) val close_process_out : out_channel -> Exit_or_signal.t (** Close channels opened by {!UnixLabels.open_process}, wait for the associated command to terminate, and return its termination status. *) val close_process : in_channel * out_channel -> Exit_or_signal.t (** Close channels opened by {!UnixLabels.open_process_full}, wait for the associated command to terminate, and return its termination status. *) val close_process_full : Process_channels.t -> Exit_or_signal.t (** {6 Symbolic links} *) (** [symlink source dest] creates the file [dest] as a symbolic link to the file [source]. *) val symlink : src:string -> dst:string -> unit (** Read the contents of a link. *) val readlink : string -> string (** {6 Polling} *) (** Wait until some input/output operations become possible on some channels. The three list arguments are, respectively, a set of descriptors to check for reading (first argument), for writing (second argument), or for exceptional conditions (third argument). The fourth argument is the maximal timeout, in seconds; a negative fourth argument means no timeout (unbounded wait). The result is composed of three sets of descriptors: those ready for reading (first component), ready for writing (second component), and over which an exceptional condition is pending (third component). *) module Select_fds : sig type t = { read : File_descr.t list; write : File_descr.t list; except : File_descr.t list; } with sexp_of val empty : t end type select_timeout = [ `Never | `Immediately | `After of Core_kernel.Time_ns.Span.t ] with sexp_of (** Setting restart to true means that we want select to restart automatically on EINTR (instead of propagating the exception)... *) val select : ?restart:bool (* defaults to false *) -> read:File_descr.t list -> write:File_descr.t list -> except:File_descr.t list -> timeout:select_timeout -> unit -> Select_fds.t (** Wait until a non-ignored, non-blocked signal is delivered. *) val pause : unit -> unit (** {6 Time functions} *) (** The execution times (CPU times) of a process. *) type process_times = Unix.process_times = { tms_utime : float; (** User time for the process *) tms_stime : float; (** System time for the process *) tms_cutime : float; (** User time for the children processes *) tms_cstime : float; (** System time for the children processes *) } with sexp (** The type representing wallclock time and calendar date. *) type tm = Unix.tm = { tm_sec : int; (** Seconds 0..59 *) tm_min : int; (** Minutes 0..59 *) tm_hour : int; (** Hours 0..23 *) tm_mday : int; (** Day of month 1..31 *) tm_mon : int; (** Month of year 0..11 *) tm_year : int; (** Year - 1900 *) tm_wday : int; (** Day of week (Sunday is 0) *) tm_yday : int; (** Day of year 0..365 *) tm_isdst : bool; (** Daylight time savings in effect *) } with sexp (** Return the current time since 00:00:00 GMT, Jan. 1, 1970, in seconds. *) val time : unit -> float (** Same as {!time} above, but with resolution better than 1 second. *) val gettimeofday : unit -> float (** Convert a time in seconds, as returned by {!UnixLabels.time}, into a date and a time. Assumes UTC. *) val gmtime : float -> tm (** Convert a UTC time in a tm record to a time in seconds *) val timegm : tm -> float (** Convert a time in seconds, as returned by {!UnixLabels.time}, into a date and a time. Assumes the local time zone. *) val localtime : float -> tm (** Convert a date and time, specified by the [tm] argument, into a time in seconds, as returned by {!UnixLabels.time}. Also return a normalized copy of the given [tm] record, with the [tm_wday], [tm_yday], and [tm_isdst] fields recomputed from the other fields. The [tm] argument is interpreted in the local time zone. *) val mktime : tm -> float * tm (** Convert a date and time, specified by the [tm] argument, into a formatted string. See 'man strftime' for format options. *) val strftime : tm -> string -> string (** Given a format string, convert a corresponding string to a date and time See 'man strptime' for format options. *) val strptime : fmt:string -> string -> Unix.tm (** Schedule a [SIGALRM] signal after the given number of seconds. *) val alarm : int -> int (** Stop execution for the given number of seconds. *) val sleep : int -> unit (** [nanosleep f] delays execution of the program for at least [f] seconds. The function can return earlier if a signal has been delivered, in which case the number of seconds left is returned. Any other failure raises an exception. *) val nanosleep : float -> float (** Return the execution times of the process. *) val times : unit -> process_times (** Set the last access time (second arg) and last modification time (third arg) for a file. Times are expressed in seconds from 00:00:00 GMT, Jan. 1, 1970. *) val utimes : string -> access:float -> modif:float -> unit (** The three kinds of interval timers. *) type interval_timer = Unix.interval_timer = ITIMER_REAL (** decrements in real time, and sends the signal [SIGALRM] when expired.*) | ITIMER_VIRTUAL (** decrements in process virtual time, and sends [SIGVTALRM] when expired. *) | ITIMER_PROF (** (for profiling) decrements both when the process is running and when the system is running on behalf of the process; it sends [SIGPROF] when expired. *) with sexp (** The type describing the status of an interval timer *) type interval_timer_status = Unix.interval_timer_status = { it_interval : float; (** Period *) it_value : float; (** Current value of the timer *) } with sexp (** Return the current status of the given interval timer. *) val getitimer : interval_timer -> interval_timer_status (** [setitimer t s] sets the interval timer [t] and returns its previous status. The [s] argument is interpreted as follows: [s.it_value], if nonzero, is the time to the next timer expiration; [s.it_interval], if nonzero, specifies a value to be used in reloading it_value when the timer expires. Setting [s.it_value] to zero disable the timer. Setting [s.it_interval] to zero causes the timer to be disabled after its next expiration. *) val setitimer : interval_timer -> interval_timer_status -> interval_timer_status (** {6 User id, group id} It's highly recommended to read the straight unix docs on these functions for more color. You can get that info from man pages or http://www.opengroup.org/onlinepubs/000095399/functions/setuid.html *) (** Return the user id of the user executing the process. *) val getuid : unit -> int (** Return the effective user id under which the process runs. *) val geteuid : unit -> int (** Sets the real user id and effective user id for the process. Only use this when superuser. To setuid as an ordinary user, see Core_extended.Unix.seteuid. *) val setuid : int -> unit (** Return the group id of the user executing the process. *) val getgid : unit -> int (** Return the effective group id under which the process runs. *) val getegid : unit -> int (** Set the real group id and effective group id for the process. *) val setgid : int -> unit (** Structure of entries in the [passwd] database *) module Passwd : sig type t = { name : string; passwd : string; uid : int; gid : int; gecos : string; dir : string; shell : string; } with sexp val getbyname : string -> t option val getbyname_exn : string -> t val getbyuid : int -> t option val getbyuid_exn : int -> t (** [getpwents] is a thread-safe wrapper over the low-level passwd database functions. *) val getpwents : unit -> t list module Low_level : sig (* These functions may not be thread safe. Use [getpwents], above, if possible. *) val setpwent : unit -> unit val getpwent : unit -> t option val getpwent_exn : unit -> t val endpwent : unit -> unit end end (** Structure of entries in the [groups] database. *) module Group : sig type t = { name : string; passwd : string; gid : int; mem : string array; } with sexp_of val getbyname : string -> t option val getbyname_exn : string -> t val getbygid : int -> t option val getbygid_exn : int -> t end (** Return the login name of the user executing the process. *) val getlogin : unit -> string module Protocol_family : sig type t = [ `Unix | `Inet | `Inet6 ] with bin_io, sexp end (** {6 Internet addresses} *) module Inet_addr : sig type t = Unix.inet_addr with bin_io, sexp include Comparable.S with type t := t (** Conversion from the printable representation of an Internet address to its internal representation. The argument string consists of 4 numbers separated by periods ([XXX.YYY.ZZZ.TTT]) for IPv4 addresses, and up to 8 numbers separated by colons for IPv6 addresses. Raise [Failure] when given a string that does not match these formats. *) val of_string : string -> t (** Call [of_string] and if that fails, use [Host.getbyname]. *) val of_string_or_getbyname : string -> t (** Return the printable representation of the given Internet address. See [of_string] for a description of the printable representation. *) val to_string : t -> string (** A special address, for use only with [bind], representing all the Internet addresses that the host machine possesses. *) val bind_any : t val bind_any_inet6 : t (** Special addresses representing the host machine. *) val localhost : t (* [127.0.0.1] *) val localhost_inet6 : t (* ([::1]) *) (** Some things (like the kernel) report addresses as hex or decimal strings. Provide conversion functions. *) val inet4_addr_of_int32 : Int32.t -> t (** [inet4_addr_to_int32_exn t = 0l] when [t = Inet_addr.of_string ("0.0.0.0")]. An exception is raised if [t] is a not an IPv4 address. *) val inet4_addr_to_int32_exn : t -> Int32.t end (** A representation of CIDR netmasks (e.g. "192.168.0.0/24") and functions to match if a given address is inside the range or not. Only IPv4 addresses are supported. *) module Cidr : sig type t with sexp, bin_io include Comparable.S_binable with type t := t (** [of_string] Generates a Cidr.t based on a string like ["10.0.0.0/8"]. Addresses are not expanded, i.e. ["10/8"] is invalid. *) include Stringable.S with type t := t val create : base_address:Inet_addr.t -> bits:int -> t (** Accessors. - [base_address 192.168.0.0/24 = 192.168.0.0] - [bits 192.168.0.0/24 = 24]. *) val base_address : t -> Inet_addr.t val bits : t -> int (** Generate a sequence of all addresses in the block. *) val all_matching_addresses : t -> Inet_addr.t Sequence.t (** IPv4 multicast address can be represented by the CIDR prefix 224.0.0.0/4, (i.e. addresses from 224.0.0.0 to 239.255.255.255, inclusive) *) val multicast : t (** Is the given address inside the given Cidr.t? Note that the broadcast and network addresses are considered valid so [does_match 10.0.0.0/8 10.0.0.0] is true. *) val does_match : t -> Inet_addr.t -> bool (** Return the netmask corresponding to the number of network bits in the CIDR. For example, the netmask for a CIDR with 24 network bits (e.g. 1.2.3.0/24) is 255.255.255.0. *) val netmask_of_bits : t -> Inet_addr.t end (** {6 Sockets} *) (** The type of socket domains. *) type socket_domain = Unix.socket_domain = | PF_UNIX (** Unix domain *) | PF_INET (** Internet domain *) | PF_INET6 (* Internet domain (IPv6) *) with sexp, bin_io (** The type of socket kinds, specifying the semantics of communications. *) type socket_type = Unix.socket_type = | SOCK_STREAM (** Stream socket *) | SOCK_DGRAM (** Datagram socket *) | SOCK_RAW (** Raw socket *) | SOCK_SEQPACKET (* Sequenced packets socket *) with sexp, bin_io (** The type of socket addresses. [ADDR_UNIX name] is a socket address in the Unix domain; [name] is a file name in the file system. [ADDR_INET(addr,port)] is a socket address in the Internet domain; [addr] is the Internet address of the machine, and [port] is the port number. *) type sockaddr = Unix.sockaddr = | ADDR_UNIX of string | ADDR_INET of Inet_addr.t * int with sexp, bin_io (** Return the socket domain adequate for the given socket address. *) val domain_of_sockaddr : sockaddr -> socket_domain (** Create a new socket in the given domain, and with the given kind. The third argument is the protocol type; 0 selects the default protocol for that kind of sockets. *) val socket : domain:socket_domain -> kind:socket_type -> protocol:int -> File_descr.t (** Create a pair of unnamed sockets, connected together. *) val socketpair : domain:socket_domain -> kind:socket_type -> protocol:int -> File_descr.t * File_descr.t (** Accept connections on the given socket. The returned descriptor is a socket connected to the client; the returned address is the address of the connecting client. *) val accept : File_descr.t -> File_descr.t * sockaddr (** Bind a socket to an address. *) val bind : File_descr.t -> addr:sockaddr -> unit (** Connect a socket to an address. *) val connect : File_descr.t -> addr:sockaddr -> unit (** Set up a socket for receiving connection requests. The integer argument is the maximal number of pending requests. *) val listen : File_descr.t -> max:int -> unit (** The type of commands for [shutdown]. *) type shutdown_command = Unix.shutdown_command = SHUTDOWN_RECEIVE (** Close for receiving *) | SHUTDOWN_SEND (** Close for sending *) | SHUTDOWN_ALL (** Close both *) with sexp (** Shutdown a socket connection. [SHUTDOWN_SEND] as second argument causes reads on the other end of the connection to return an end-of-file condition. [SHUTDOWN_RECEIVE] causes writes on the other end of the connection to return a closed pipe condition ([SIGPIPE] signal). *) val shutdown : File_descr.t -> mode:shutdown_command -> unit (** Return the address of the given socket. *) val getsockname : File_descr.t -> sockaddr (** Return the address of the host connected to the given socket. *) val getpeername : File_descr.t -> sockaddr (** The flags for {!UnixLabels.recv}, {!UnixLabels.recvfrom}, {!UnixLabels.send} and {!UnixLabels.sendto}. *) type msg_flag = Unix.msg_flag = MSG_OOB | MSG_DONTROUTE | MSG_PEEK with sexp (** Receive data from a connected socket. *) val recv : File_descr.t -> buf:string -> pos:int -> len:int -> mode:msg_flag list -> int (** Receive data from an unconnected socket. *) val recvfrom : File_descr.t -> buf:string -> pos:int -> len:int -> mode:msg_flag list -> int * sockaddr (** Send data over a connected socket. *) val send : File_descr.t -> buf:string -> pos:int -> len:int -> mode:msg_flag list -> int (** Send data over an unconnected socket. *) val sendto : File_descr.t -> buf:string -> pos:int -> len:int -> mode:msg_flag list -> addr:sockaddr -> int (** {6 Socket options} *) (** The socket options that can be consulted with {!UnixLabels.getsockopt} and modified with {!UnixLabels.setsockopt}. These options have a boolean ([true]/[false]) value. *) type socket_bool_option = SO_DEBUG (** Record debugging information *) | SO_BROADCAST (** Permit sending of broadcast messages *) | SO_REUSEADDR (** Allow reuse of local addresses for bind *) | SO_KEEPALIVE (** Keep connection active *) | SO_DONTROUTE (** Bypass the standard routing algorithms *) | SO_OOBINLINE (** Leave out-of-band data in line *) | SO_ACCEPTCONN (* Report whether socket listening is enabled *) | TCP_NODELAY (** Control the Nagle algorithm for TCP sockets *) | IPV6_ONLY (** Forbid binding an IPv6 socket to an IPv4 address *) with sexp (** The socket options that can be consulted with {!UnixLabels.getsockopt_int} and modified with {!UnixLabels.setsockopt_int}. These options have an integer value. *) type socket_int_option = SO_SNDBUF (** Size of send buffer *) | SO_RCVBUF (** Size of received buffer *) | SO_ERROR (** Report the error status and clear it *) | SO_TYPE (** Report the socket type *) | SO_RCVLOWAT (** Minimum number of bytes to process for input operations *) | SO_SNDLOWAT (* Minimum number of bytes to process for output operations *) with sexp (** The socket options that can be consulted with {!UnixLabels.getsockopt_optint} and modified with {!UnixLabels.setsockopt_optint}. These options have a value of type [int option], with [None] meaning ``disabled''. *) type socket_optint_option = SO_LINGER (** Whether to linger on closed connections with sexp that have data present, and for how long (in seconds) *) (** The socket options that can be consulted with {!UnixLabels.getsockopt_float} and modified with {!UnixLabels.setsockopt_float}. These options have a floating-point value representing a time in seconds. The value 0 means infinite timeout. *) type socket_float_option = SO_RCVTIMEO (** Timeout for input operations *) | SO_SNDTIMEO (** Timeout for output operations *) with sexp (** Return the current status of a boolean-valued option in the given socket. *) val getsockopt : File_descr.t -> socket_bool_option -> bool (** Set or clear a boolean-valued option in the given socket. *) val setsockopt : File_descr.t -> socket_bool_option -> bool -> unit (** Same as {!UnixLabels.getsockopt} for an integer-valued socket option. *) val getsockopt_int : File_descr.t -> socket_int_option -> int (** Same as {!UnixLabels.setsockopt} for an integer-valued socket option. *) val setsockopt_int : File_descr.t -> socket_int_option -> int -> unit (** Same as {!UnixLabels.getsockopt} for a socket option whose value is an [int option]. *) val getsockopt_optint : File_descr.t -> socket_optint_option -> int option (** Same as {!UnixLabels.setsockopt} for a socket option whose value is an [int option]. *) val setsockopt_optint : File_descr.t -> socket_optint_option -> int option -> unit (** Same as {!UnixLabels.getsockopt} for a socket option whose value is a floating-point number. *) val getsockopt_float : File_descr.t -> socket_float_option -> float (** Same as {!UnixLabels.setsockopt} for a socket option whose value is a floating-point number. *) val setsockopt_float : File_descr.t -> socket_float_option -> float -> unit (** {6 High-level network connection functions} *) (** Connect to a server at the given address. Return a pair of buffered channels connected to the server. Remember to call {!Pervasives.flush} on the output channel at the right times to ensure correct synchronization. *) val open_connection : sockaddr -> in_channel * out_channel (** ``Shut down'' a connection established with {!UnixLabels.open_connection}; that is, transmit an end-of-file condition to the server reading on the other side of the connection. *) val shutdown_connection : in_channel -> unit (** Establish a server on the given address. The function given as first argument is called for each connection with two buffered channels connected to the client. A new process is created for each connection. The function {!UnixLabels.establish_server} never returns normally. *) val establish_server : (in_channel -> out_channel -> unit) -> addr:sockaddr -> unit (** {6 Host and protocol databases} *) (** Return the name of the local host. *) val gethostname : unit -> string module Host : sig (** Structure of entries in the [hosts] database. *) type t = { name : string; aliases : string array; family : Protocol_family.t; addresses : Inet_addr.t array; } with sexp_of (** Find an entry in [hosts] with the given name. NOTE: This function is not thread safe with certain versions of winbind using "wins" name resolution. *) val getbyname : string -> t option val getbyname_exn : string -> t (** Find an entry in [hosts] with the given address. *) val getbyaddr : Inet_addr.t -> t option val getbyaddr_exn : Inet_addr.t -> t val have_address_in_common : t -> t -> bool end module Protocol : sig (** Structure of entries in the [protocols] database. *) type t = { name : string; aliases : string array; proto : int; } with sexp (** Find an entry in [protocols] with the given name. *) val getbyname : string -> t option val getbyname_exn : string -> t (** Find an entry in [protocols] with the given protocol number. *) val getbynumber : int -> t option val getbynumber_exn : int -> t end module Service : sig (** Structure of entries in the [services] database. *) type t = { name : string; aliases : string array; port : int; proto : string; } with sexp (** Find an entry in [services] with the given name. *) val getbyname : string -> protocol:string -> t option val getbyname_exn : string -> protocol:string -> t (** Find an entry in [services] with the given service number. *) val getbyport : int -> protocol:string -> t option val getbyport_exn : int -> protocol:string -> t end (** Address information returned by {!Unix.getaddrinfo}. *) type addr_info = { ai_family : socket_domain; (** Socket domain *) ai_socktype : socket_type; (** Socket type *) ai_protocol : int; (** Socket protocol number *) ai_addr : sockaddr; (** Address *) ai_canonname : string (* Canonical host name *) } with sexp (** Options to {!Unix.getaddrinfo}. *) type getaddrinfo_option = AI_FAMILY of socket_domain (** Impose the given socket domain *) | AI_SOCKTYPE of socket_type (** Impose the given socket type *) | AI_PROTOCOL of int (** Impose the given protocol *) | AI_NUMERICHOST (** Do not call name resolver, expect numeric IP address *) | AI_CANONNAME (** Fill the [ai_canonname] field of the result *) | AI_PASSIVE (* Set address to ``any'' address for use with {!Unix.bind} *) with sexp (** [getaddrinfo host service opts] returns a list of {!Unix.addr_info} records describing socket parameters and addresses suitable for communicating with the given host and service. The empty list is returned if the host or service names are unknown, or the constraints expressed in [opts] cannot be satisfied. [host] is either a host name or the string representation of an IP address. [host] can be given as the empty string; in this case, the ``any'' address or the ``loopback'' address are used, depending whether [opts] contains [AI_PASSIVE]. [service] is either a service name or the string representation of a port number. [service] can be given as the empty string; in this case, the port field of the returned addresses is set to 0. [opts] is a possibly empty list of options that allows the caller to force a particular socket domain (e.g. IPv6 only, or IPv4 only) or a particular socket type (e.g. TCP only or UDP only). *) val getaddrinfo : string -> string -> getaddrinfo_option list -> addr_info list (** Host and service information returned by {!Unix.getnameinfo}. *) type name_info = { ni_hostname : string; (** Name or IP address of host *) ni_service : string; } (** Name of service or port number *) with sexp (** Options to {!Unix.getnameinfo}. *) type getnameinfo_option = NI_NOFQDN (** Do not qualify local host names *) | NI_NUMERICHOST (** Always return host as IP address *) | NI_NAMEREQD (** Fail if host name cannot be determined *) | NI_NUMERICSERV (** Always return service as port number *) | NI_DGRAM (* Consider the service as UDP-based instead of the default TCP *) with sexp (** [getnameinfo addr opts] returns the host name and service name corresponding to the socket address [addr]. [opts] is a possibly empty list of options that governs how these names are obtained. Raise [Not_found] if an error occurs. *) val getnameinfo : sockaddr -> getnameinfo_option list -> name_info (** {2 Getting terminal size} *) (** {6 Terminal interface} *) (** The following functions implement the POSIX standard terminal interface. They provide control over asynchronous communication ports and pseudo-terminals. Refer to the [termios] man page for a complete description. *) module Terminal_io : sig type t = Unix.terminal_io = { (* Input modes: *) mutable c_ignbrk : bool; (** Ignore the break condition. *) mutable c_brkint : bool; (** Signal interrupt on break condition. *) mutable c_ignpar : bool; (** Ignore characters with parity errors. *) mutable c_parmrk : bool; (** Mark parity errors. *) mutable c_inpck : bool; (** Enable parity check on input. *) mutable c_istrip : bool; (** Strip 8th bit on input characters. *) mutable c_inlcr : bool; (** Map NL to CR on input. *) mutable c_igncr : bool; (** Ignore CR on input. *) mutable c_icrnl : bool; (** Map CR to NL on input. *) mutable c_ixon : bool; (** Recognize XON/XOFF characters on input. *) mutable c_ixoff : bool; (** Emit XON/XOFF chars to control input flow. *) (* Output modes: *) mutable c_opost : bool; (** Enable output processing. *) (* Control modes: *) mutable c_obaud : int; (** Output baud rate (0 means close connection).*) mutable c_ibaud : int; (** Input baud rate. *) mutable c_csize : int; (** Number of bits per character (5-8). *) mutable c_cstopb : int; (** Number of stop bits (1-2). *) mutable c_cread : bool; (** Reception is enabled. *) mutable c_parenb : bool; (** Enable parity generation and detection. *) mutable c_parodd : bool; (** Specify odd parity instead of even. *) mutable c_hupcl : bool; (** Hang up on last close. *) mutable c_clocal : bool; (** Ignore modem status lines. *) (* Local modes: *) mutable c_isig : bool; (** Generate signal on INTR, QUIT, SUSP. *) mutable c_icanon : bool; (** Enable canonical processing (line buffering and editing) *) mutable c_noflsh : bool; (** Disable flush after INTR, QUIT, SUSP. *) mutable c_echo : bool; (** Echo input characters. *) mutable c_echoe : bool; (** Echo ERASE (to erase previous character). *) mutable c_echok : bool; (** Echo KILL (to erase the current line). *) mutable c_echonl : bool; (** Echo NL even if c_echo is not set. *) (* Control characters: *) mutable c_vintr : char; (** Interrupt character (usually ctrl-C). *) mutable c_vquit : char; (** Quit character (usually ctrl-\). *) mutable c_verase : char; (** Erase character (usually DEL or ctrl-H). *) mutable c_vkill : char; (** Kill line character (usually ctrl-U). *) mutable c_veof : char; (** End-of-file character (usually ctrl-D). *) mutable c_veol : char; (** Alternate end-of-line char. (usually none). *) mutable c_vmin : int; (** Minimum number of characters to read before the read request is satisfied. *) mutable c_vtime : int; (** Maximum read wait (in 0.1s units). *) mutable c_vstart : char; (** Start character (usually ctrl-Q). *) mutable c_vstop : char; (** Stop character (usually ctrl-S). *) } with sexp_of type setattr_when = Unix.setattr_when = TCSANOW | TCSADRAIN | TCSAFLUSH with sexp_of (** Return the status of the terminal referred to by the given file descriptor. *) val tcgetattr : File_descr.t -> t (** Set the status of the terminal referred to by the given file descriptor. The second argument indicates when the status change takes place: immediately ([TCSANOW]), when all pending output has been transmitted ([TCSADRAIN]), or after flushing all input that has been received but not read ([TCSAFLUSH]). [TCSADRAIN] is recommended when changing the output parameters; [TCSAFLUSH], when changing the input parameters. *) val tcsetattr : t -> File_descr.t -> mode:setattr_when -> unit (** Send a break condition on the given file descriptor. The second argument is the duration of the break, in 0.1s units; 0 means standard duration (0.25s). *) val tcsendbreak : File_descr.t -> duration:int -> unit (** Waits until all output written on the given file descriptor has been transmitted. *) val tcdrain : File_descr.t -> unit type flush_queue = Unix.flush_queue = TCIFLUSH | TCOFLUSH | TCIOFLUSH with sexp (** Discard data written on the given file descriptor but not yet transmitted, or data received but not yet read, depending on the second argument: [TCIFLUSH] flushes data received but not read, [TCOFLUSH] flushes data written but not transmitted, and [TCIOFLUSH] flushes both. *) val tcflush : File_descr.t -> mode:flush_queue -> unit type flow_action = Unix.flow_action = | TCOOFF | TCOON | TCIOFF | TCION with sexp (** Suspend or restart reception or transmission of data on the given file descriptor, depending on the second argument: [TCOOFF] suspends output, [TCOON] restarts output, [TCIOFF] transmits a STOP character to suspend input, and [TCION] transmits a START character to restart input. *) val tcflow : File_descr.t -> mode:flow_action -> unit (** Put the calling process in a new session and detach it from its controlling terminal. *) val setsid : unit -> int end (** Get a sockaddr from a hostname or IP, and a port *) val get_sockaddr : string -> int -> sockaddr (** Set a timeout for a socket associated with an [in_channel] *) val set_in_channel_timeout : in_channel -> float -> unit (** Set a timeout for a socket associated with an [out_channel] *) val set_out_channel_timeout : out_channel -> float -> unit (** [exit_immediately exit_code] immediately calls the [exit] system call with the given exit code without performing any other actions (unlike Pervasives.exit). Does not return. *) val exit_immediately : int -> _ (** {2 Filesystem functions} *) (** [mknod ?file_kind ?perm ?major ?minor path] creates a filesystem entry. Note that only FIFO-entries are guaranteed to be supported across all platforms as required by the POSIX-standard. On Linux directories and symbolic links cannot be created with this function. Use {!Unix.mkdir} and {!Unix.symlink} instead there respectively. @raise Invalid_argument if an unsupported file kind is used. @raise Unix_error if the system call fails. @param file_kind default = [S_REG] (= regular file) @param perm default = [0o600] (= read/write for user only) @param major default = [0] @param minor default = [0] *) val mknod : ?file_kind : file_kind -> ?perm : int -> ?major : int -> ?minor : int -> string -> unit (** {2 I/O vectors} *) (** I/O-vectors for scatter/gather-operations *) module IOVec : sig open Bigarray (** Representation of I/O-vectors. NOTE: DO NOT CHANGE THE MEMORY LAYOUT OF THIS TYPE!!! All C-functions in our bindings that handle I/O-vectors depend on it. *) type 'buf t = private { buf : 'buf; (** Buffer holding the I/O-vector *) pos : int; (** Position of I/O-vector in buffer *) len : int; (** Length of I/O-vector in buffer *) } with sexp type 'buf kind (** Kind of I/O-vector buffers *) type bigstring = (char, int8_unsigned_elt, c_layout) Array1.t val string_kind : string kind val bigstring_kind : bigstring kind val empty : 'buf kind -> 'buf t (** [empty] the empty I/O-vector. *) val of_string : ?pos : int -> ?len : int -> string -> string t (** [of_string ?pos ?len str] @return an I/O-vector designated by position [pos] and length [len] in string [str]. @raise Invalid_argument if designated substring out of bounds. @param pos default = 0 @param len default = [String.length str - pos] *) val of_bigstring : ?pos : int -> ?len : int -> bigstring -> bigstring t (** [of_bigstring ?pos ?len bstr] @return an I/O-vector designated by position [pos] and length [len] in bigstring [bstr]. @raise Invalid_argument if designated substring out of bounds. @param pos default = 0 @param len default = [String.length str - pos] *) val drop : 'buf t -> int -> 'buf t (** [drop iovec n] drops [n] characters from [iovec]. @return resulting I/O-vector. @raise Failure if [n] is greater than length of [iovec]. *) val max_iovecs : int end (** {2 I/O functions} *) external dirfd : dir_handle -> File_descr.t = "unix_dirfd" (** Extract a file descriptor from a directory handle. *) external sync : unit -> unit = "unix_sync" (** Synchronize all filesystem buffers with disk. *) external fsync : File_descr.t -> unit = "unix_fsync" (** Synchronize the kernel buffers of a given file descriptor with disk, but do not necessarily write file attributes. *) external fdatasync : File_descr.t -> unit = "unix_fdatasync" external readdir_ino : dir_handle -> string * nativeint = "unix_readdir_ino_stub" (** [readdir_ino dh] return the next entry in a directory (([(filename, inode)]). @raise End_of_file when the end of the directory has been reached. *) val read_assume_fd_is_nonblocking : File_descr.t -> ?pos : int -> ?len : int -> string -> int (** [read_assume_fd_is_nonblocking fd ?pos ?len buf] calls the system call [read] ASSUMING THAT IT IS NOT GOING TO BLOCK. Reads at most [len] bytes into buffer [buf] starting at position [pos]. @return the number of bytes actually read. @raise Invalid_argument if buffer range out of bounds. @raise Unix_error on Unix-errors. @param pos = 0 @param len = [String.length buf - pos] *) val write_assume_fd_is_nonblocking : File_descr.t -> ?pos : int -> ?len : int -> string -> int (** [write_assume_fd_is_nonblocking fd ?pos ?len buf] calls the system call [write] ASSUMING THAT IT IS NOT GOING TO BLOCK. Writes at most [len] bytes from buffer [buf] starting at position [pos]. @return the number of bytes actually written. @raise Invalid_argument if buffer range out of bounds. @raise Unix_error on Unix-errors. @param pos = 0 @param len = [String.length buf - pos] *) val writev_assume_fd_is_nonblocking : File_descr.t -> ?count : int -> string IOVec.t array -> int (** [writev_assume_fd_is_nonblocking fd ?count iovecs] calls the system call [writev] ASSUMING THAT IT IS NOT GOING TO BLOCK using [count] I/O-vectors [iovecs]. @return the number of bytes actually written. @raise Invalid_argument if the designated ranges are invalid. @raise Unix_error on Unix-errors. *) val writev : File_descr.t -> ?count : int -> string IOVec.t array -> int (** [writev fd ?count iovecs] like {!writev_assume_fd_is_nonblocking}, but does not require the descriptor to not block. If you feel you have to use this function, you should probably have chosen I/O-vectors that build on bigstrings, because this function has to internally blit the I/O-vectors (ordinary OCaml strings) to intermediate buffers on the C-heap. @return the number of bytes actually written. @raise Invalid_argument if the designated ranges are invalid. @raise Unix_error on Unix-errors. *) external pselect : File_descr.t list -> File_descr.t list -> File_descr.t list -> float -> int list -> File_descr.t list * File_descr.t list * File_descr.t list = "unix_pselect_stub" (** [pselect rfds wfds efds timeout sigmask] like {!Core_unix.select} but also allows one to wait for the arrival of signals. *) (** {2 Resource limits} *) module RLimit : sig type limit = Limit of int64 | Infinity with sexp type t = { cur : limit; (* soft limit *) max : limit; (* hard limit (ceiling for soft limit) *) } with sexp type resource with sexp val core_file_size : resource val cpu_seconds : resource val data_segment : resource val file_size : resource val num_file_descriptors : resource val stack : resource val virtual_memory : resource Or_error.t val nice : resource Or_error.t (* See man pages for "getrlimit" and "setrlimit" for details. *) val get : resource -> t val set : resource -> t -> unit end (** {2 Resource usage} -- For details, "man getrusage" *) module Resource_usage : sig type t = { utime : float; stime : float; maxrss : int64; ixrss : int64; idrss : int64; isrss : int64; minflt : int64; majflt : int64; nswap : int64; inblock : int64; oublock : int64; msgsnd : int64; msgrcv : int64; nsignals : int64; nvcsw : int64; nivcsw : int64; } with sexp, fields val get : [`Self | `Children] -> t (** [add ru1 ru2] adds two rusage structures (e.g. your resource usage and your children's). *) val add : t -> t -> t end (** {2 System configuration} *) type sysconf = | ARG_MAX | CHILD_MAX | HOST_NAME_MAX | LOGIN_NAME_MAX | OPEN_MAX | PAGESIZE | RE_DUP_MAX | STREAM_MAX | SYMLOOP_MAX | TTY_NAME_MAX | TZNAME_MAX | POSIX_VERSION | PHYS_PAGES | AVPHYS_PAGES | IOV_MAX with sexp external sysconf : sysconf -> int64 = "unix_sysconf" (** {2 Temporary file and directory creation} *) (** [mkstemp prefix] creates and opens a unique temporary file with [prefix], automatically appending a suffix of six random characters to make the name unique. Unlike C's [mkstemp], [prefix] should not include six X's at the end. @raise Unix_error on errors. *) val mkstemp : string -> string * File_descr.t (** [mkdtemp prefix] creates a temporary directory with [prefix], automatically appending a suffix of six random characters to make the name unique. @raise Unix_error on errors. k*) val mkdtemp : string -> string (** {2 Signal handling} *) (* Causes abnormal program termination unless the signal SIGABRT is caught and the signal handler does not return. If the SIGABRT signal is blocked or ignored, the abort() function will still override it. *) external abort : unit -> _ = "unix_abort" "noalloc" (** {2 User id, group id} *) external initgroups : string -> int -> unit = "unix_initgroups" (** [getgrouplist user group] returns the list of groups to which [user] belongs. See 'man getgrouplist'. *) val getgrouplist : string -> int -> int array (** Return the list of groups to which the user executing the process belongs. *) val getgroups : unit -> int array (** {2 Globbing and shell expansion} *) (* no system calls involved *) val fnmatch : ?flags : [ `No_escape | `Pathname | `Period | `File_name | `Leading_dir | `Casefold ] list -> pat : string -> string -> bool (* See man page for wordexp. *) val wordexp : (?flags : [ `No_cmd | `Show_err | `Undef ] list -> string -> string array) Or_error.t (** {2 System information} *) module Utsname : sig type t with sexp val sysname : t -> string val nodename : t -> string val release : t -> string val version : t -> string val machine : t -> string end (* See man page for uname. *) val uname : unit -> Utsname.t (** {2 Additional IP functionality} *) (* [if_indextoname ifindex] If [ifindex] is an interface index, then the function returns the interface name. Otherwise, it raises [Unix_error]. *) val if_indextoname : int -> string (** [mcast_join ?ifname sock addr] join a multicast group at [addr] with socket [sock], from source at [source] if specified, optionally using network interface [ifname]. @param ifname default = any interface *) val mcast_join : ?ifname : string -> ?source : Inet_addr.t -> File_descr.t -> sockaddr -> unit (** [mcast_leave ?ifname sock addr] leaves a multicast group at [addr] with socket [sock], optionally using network interface [ifname]. @param ifname default = any interface *) val mcast_leave : ?ifname : string -> File_descr.t -> sockaddr -> unit (** [get_mcast_ttl sock] reads the time-to-live value of outgoing multicast packets for socket [sock]. *) val get_mcast_ttl : File_descr.t -> int (** [set_mcast_ttl sock ttl] sets the time-to-live value of outgoing multicast packets for socket [sock] to [ttl]. *) val set_mcast_ttl : File_descr.t -> int -> unit (** [get_mcast_loop sock] reads the boolean argument that determines whether sent multicast packets are looped back to local sockets. *) val get_mcast_loop : File_descr.t -> bool (** [set_mcast_loop sock loop] sets the boolean argument that determines whether sent multicast packets are looped back to local sockets. *) val set_mcast_loop : File_descr.t -> bool -> unit (** [set_mcast_ifname sock "eth0"] sets outgoing multicast traffic on IPv4 UDP socket [sock] to go out through interface [eth0]. This uses [setsockopt] with [IP_MULTICAST_IF] and applies to multicast traffic. For non-multicast applications, see {!Linux_ext.bind_to_interface}. *) val set_mcast_ifname : File_descr.t -> string -> unit module Scheduler : sig module Policy : sig type t = [ `Fifo | `Round_robin | `Other ] with sexp end (* See [man sched_setscheduler]. The [priority] supplied here is *not* the nice value of a process. It is the "static" priority (1 .. 99) used in conjunction with real-time processes. If you want to set the nice value of a normal process, use [Linux_ext.setpriority] or [Core_unix.nice]. *) val set : pid:Pid.t option -> policy : Policy.t -> priority : int -> unit end module Priority : sig external nice : int -> int = "unix_nice" end (* For keeping your memory in RAM, i.e. preventing it from being swapped out. *) module Mman : sig module Mcl_flags : sig type t = Current | Future with sexp end (* Lock all pages in this process's virtual address space into physical memory. See [man mlockall] for more details. *) val mlockall : Mcl_flags.t list -> unit (* Unlock previously locked pages. See [man munlockall]. *) val munlockall : unit -> unit end module Syslog : module type of Syslog (* vim: set filetype=ocaml : *) core-113.00.00/src/crc.ml000066400000000000000000000024071256461075500146520ustar00rootroot00000000000000open Core_kernel.Std external crc32 : string -> Int63.t = "core_crc_string_crc32" external unsafe_bigstring_crc32 : Bigstring.t -> pos:int -> len:int -> Int63.t = "core_crc_bigstring_crc32" let bigstring_crc32 bstr ~pos ~len = let length = Bigstring.length bstr in Ordered_collection_common.check_pos_len_exn ~pos ~len ~length; unsafe_bigstring_crc32 bstr ~pos ~len let crc32hex s = Printf.sprintf "%08LX" (Int63.to_int64 (crc32 s)) TEST_MODULE = struct let str = "The quick brown fox jumps over the lazy dog" let len = String.length str let crc = Int63.of_int64_exn 0x414fa339L let bstr = Bigstring.of_string str TEST_UNIT = <:test_result< Int63.Hex.t >> (crc32 str) ~expect:crc TEST_UNIT = <:test_result< Int63.Hex.t >> (bigstring_crc32 bstr ~pos:0 ~len) ~expect:crc TEST_UNIT = <:test_result< Int63.Hex.t >> (bigstring_crc32 (Bigstring.of_string ("12345" ^ str ^ "12345")) ~pos:5 ~len) ~expect:crc TEST = does_raise (fun () -> bigstring_crc32 bstr ~pos:0 ~len:(-1)) TEST = does_raise (fun () -> bigstring_crc32 bstr ~pos:0 ~len:(len+1)) TEST = does_raise (fun () -> bigstring_crc32 bstr ~pos:(-1) ~len:0) TEST = does_raise (fun () -> bigstring_crc32 bstr ~pos:(len+1) ~len:0) end core-113.00.00/src/crc.mli000066400000000000000000000003761256461075500150260ustar00rootroot00000000000000(** Crc functions *) open Core_kernel.Std (** Compute the 32-bit crc *) val crc32 : string -> Int63.t val bigstring_crc32 : Bigstring.t -> pos:int -> len:int -> Int63.t (** String version of the crc, encoded in hex. *) val crc32hex : string -> string core-113.00.00/src/crc_stubs.c000066400000000000000000000041231256461075500157010ustar00rootroot00000000000000#include #include #include #include "unix_utils.h" /* This file is based on code with the following header: */ /* Copyright abandoned; this code is in the public domain. */ /* Provided to GNUnet by peter@horizon.com */ /** * @file util/crc32.c * @brief implementation of CRC32 **/ /* #include "gnunet_util.h" */ #define POLYNOMIAL ((unsigned int) 0xedb88320) static unsigned int crc_table[256]; /* * This routine writes each crc_table entry exactly once, with the * correct final value. Thus, it is safe to call even on a table that * someone else is using concurrently. */ static void make_crc_table() { unsigned int i, j; unsigned int h = 1; crc_table[0] = 0; for (i = 128; i; i >>= 1) { h = (h >> 1) ^ ((h & 1) ? POLYNOMIAL : 0); /* h is now crc_table[i] */ for (j = 0; j < 256; j += 2*i) crc_table[i+j] = crc_table[j] ^ h; } } /* * This computes the standard preset and inverted CRC, as used by most * networking standards. Start by passing in an initial chaining * value of 0, and then pass in the return value from the previous * crc32() call. The final return value is the CRC. Note that this * is a little-endian CRC, which is best used with data transmitted * lsbit-first, and it should, itself, be appended to data in * little-endian byte and bit order to preserve the property of * detecting all burst errors of length 32 bits or less. */ static unsigned int crc32(unsigned int crc, char const *buf, size_t len) { if (crc_table[255] == 0) make_crc_table(); crc ^= 0xffffffff; while (len--) crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; return crc ^ 0xffffffff; } value core_crc_string_crc32 (value v_str) { char *octets = String_val (v_str); size_t len = caml_string_length (v_str); unsigned int crc = crc32 (0, octets, len); return caml_alloc_int63 (crc); } value core_crc_bigstring_crc32 (value v_bstr, value v_pos, value v_len) { char *octets = get_bstr (v_bstr, v_pos); size_t len = Long_val (v_len); unsigned int crc = crc32 (0, octets, len); return caml_alloc_int63 (crc); } core-113.00.00/src/daemon.ml000066400000000000000000000131071256461075500153450ustar00rootroot00000000000000open Core_kernel.Std module Unix = Core_unix module Thread = Core_thread let check_threads () = (* forking, especially to daemonize, when running multiple threads is tricky, and generally a mistake. It's so bad, and so hard to catch, that we test in two different ways *) if Thread.threads_have_been_created () then failwith "Daemon.check_threads: may not be called \ if any threads have ever been created"; begin match Thread.num_threads () with | None -> () (* This is pretty bad, but more likely to be a problem with num_threads *) | Some (1 | 2) -> () (* main thread, or main + ticker - both ok *) | Some _ -> failwith "Daemon.check_threads: may not be called if more than 2 threads \ (hopefully the main thread + ticker thread) are running" end; ;; module Fd_redirection = struct type do_redirect = [ `Dev_null | `File_append of string | `File_truncate of string ] type t = [ `Do_not_redirect | do_redirect ] end ;; let redirect_fd ~skip_regular_files ~mode ~src ~dst = match src with | `Do_not_redirect -> () | #Fd_redirection.do_redirect as src -> let is_regular () = try (Unix.fstat dst).Unix.st_kind = Unix.S_REG with Unix.Unix_error (EBADF, _, _) -> false in let should_skip = skip_regular_files && is_regular () in if not should_skip then begin let src = match src with | `Dev_null -> Unix.openfile "/dev/null" ~mode:[mode] ~perm:0o777 | `File_append file -> Unix.openfile file ~mode:[mode; Unix.O_CREAT; Unix.O_APPEND] | `File_truncate file -> Unix.openfile file ~mode:[mode; Unix.O_CREAT; Unix.O_TRUNC] in Unix.dup2 ~src ~dst; Unix.close src; end; ;; let redirect_stdio_fds ~skip_regular_files ~stdout ~stderr = redirect_fd ~skip_regular_files ~mode:Unix.O_RDONLY ~src:`Dev_null ~dst:Unix.stdin; redirect_fd ~skip_regular_files ~mode:Unix.O_WRONLY ~src:stdout ~dst:Unix.stdout; redirect_fd ~skip_regular_files ~mode:Unix.O_WRONLY ~src:stderr ~dst:Unix.stderr; ;; let daemonize ?(redirect_stdout=`Dev_null) ?(redirect_stderr=`Dev_null) ?(cd = "/") ?umask () = check_threads (); let fork_no_parent () = match Unix.handle_unix_error Unix.fork with | `In_the_child -> () | `In_the_parent _ -> exit 0 in (* Fork into the background, parent exits, child continues. *) fork_no_parent (); (* Become session leader. *) ignore (Unix.Terminal_io.setsid ()); (* Fork again to ensure that we will never regain a controlling terminal. *) fork_no_parent (); (* Release old working directory. *) Unix.chdir cd; (* Ensure sensible umask. Adjust as needed. *) Option.iter umask ~f:(fun umask -> ignore (Unix.umask umask)); redirect_stdio_fds ~skip_regular_files:false ~stdout:redirect_stdout ~stderr:redirect_stderr; ;; let fail_wstopped ~pid ~i = failwithf "Bug: waitpid on process %i returned WSTOPPED %i, \ but waitpid not called with WUNTRACED. This should not happen" pid i () let daemonize_wait ?(redirect_stdout=`Dev_null) ?(redirect_stderr=`Dev_null) ?(cd = "/") ?umask () = check_threads (); match Unix.handle_unix_error Unix.fork with | `In_the_child -> ignore (Unix.Terminal_io.setsid ()); let read_end, write_end = Unix.pipe () in let buf = "done" in let len = String.length buf in begin match Unix.handle_unix_error Unix.fork with | `In_the_child -> (* The process that will become the actual daemon. *) Unix.close read_end; Unix.chdir cd; Option.iter umask ~f:(fun umask -> ignore (Unix.umask umask)); Staged.stage (fun () -> redirect_stdio_fds ~skip_regular_files:true ~stdout:redirect_stdout ~stderr:redirect_stderr; let old_sigpipe_behavior = Signal.Expert.signal Signal.pipe `Ignore in (try ignore (Unix.write write_end ~buf ~pos:0 ~len : int) with _ -> ()); Signal.Expert.set Signal.pipe old_sigpipe_behavior; Unix.close write_end ) | `In_the_parent pid -> let pid = Pid.to_int pid in (* The middle process, after it has forked its child. *) Unix.close write_end; let rec loop () = let wait_result, process_status = UnixLabels.waitpid ~mode:[UnixLabels.WNOHANG] pid in if wait_result = 0 then begin match Unix.select ~read:[read_end] ~write:[] ~except:[] ~timeout:(`After (Time_ns.Span.of_sec 0.1)) () with | { Unix.Select_fds. read = [read_end]; write = []; except = [] } -> (* If the child process exits before detaching and the middle process happens to be in this call to select, the pipe will be closed and select will return a ready file descriptor, but with zero bytes to read. In this case, we want to loop back again and call waitpid to obtain the correct exit status to propagate on to the outermost parent (otherwise we might incorrectly return a success). *) if Unix.read read_end ~buf:(String.create len) ~pos:0 ~len > 0 then exit 0 else loop () | _ -> loop () end else match process_status with | UnixLabels.WEXITED i | UnixLabels.WSIGNALED i -> exit i | UnixLabels.WSTOPPED i -> fail_wstopped ~pid ~i in loop () end | `In_the_parent pid -> let pid = Pid.to_int pid in match snd (UnixLabels.waitpid ~mode:[] pid) with | UnixLabels.WEXITED i | UnixLabels.WSIGNALED i -> exit i | UnixLabels.WSTOPPED i -> fail_wstopped ~pid ~i ;; core-113.00.00/src/daemon.mli000066400000000000000000000046701256461075500155230ustar00rootroot00000000000000(** This module provides support for daemonizing a process. It provides flexibility as to where the standard file descriptors (stdin, stdout and stderr) are connected after daemonization has occurred. *) open Core_kernel.Std module Fd_redirection : sig type t = [ | `Dev_null | `Do_not_redirect | `File_append of string | `File_truncate of string ] end (** [daemonize] makes the executing process a daemon. See Chapter 13 of Advanced Programming in the UNIX Environment Second Edition by Stephens and Rago for more details. The optional arguments have defaults as per [daemonize_wait], below. By default, output sent to stdout and stderr after daemonization will be silently eaten. This behaviour may be adjusted by using [redirect_stdout] and [redirect_stderr]. See the documentation for [daemonize_wait] below. @raise Failure if fork was unsuccessful. *) val daemonize : ?redirect_stdout : Fd_redirection.t -> ?redirect_stderr : Fd_redirection.t -> ?cd : string -> ?umask : int (** defaults to use existing umask *) -> unit -> unit (** [daemonize_wait] makes the executing process a daemon, but delays full detachment from the calling shell/process until the returned "release" closure is called. Any output to stdout/stderr before the "release" closure is called will get sent out normally. After "release" is called, stdin is connected to /dev/null, and stdout and stderr are connected as specified by [redirect_stdout] and [redirect_stderr]. The default is the usual behaviour whereby both of these descriptors are connected to /dev/null. Note that calling [release] will adjust SIGPIPE handling, so you should not rely on the delivery of this signal during this time. [daemonize_wait] allows you to daemonize and then start async, but still have stdout/stderr go to the controlling terminal during startup. By default, when you [daemonize], toplevel exceptions during startup would get sent to /dev/null. With [daemonize_wait], toplevel exceptions can go to the terminal until you call [release]. @raise Failure if fork was unsuccessful. *) val daemonize_wait : ?redirect_stdout : Fd_redirection.t (** default redirect to /dev/null *) -> ?redirect_stderr : Fd_redirection.t (** default redirect to /dev/null *) -> ?cd : string (** default / *) -> ?umask : int (** defaults to use existing umask *) -> unit -> (unit -> unit) Staged.t core-113.00.00/src/date.ml000066400000000000000000000023731256461075500150220ustar00rootroot00000000000000include Date0 let of_time time ~zone = Time.to_date ~zone time let today ~zone = of_time (Time.now ()) ~zone let format date pat = let time = Time.of_date_ofday ~zone:Zone.local date Ofday.start_of_day in Time.format time pat ;; TEST_MODULE "week_number" = struct TEST_UNIT = let module Error = Core_kernel.Error in let module Result = Core_kernel.Result in let module Or_error = Core_kernel.Or_error in let start_date = create_exn ~y:2000 ~m:Jan ~d:1 in let stop_date = create_exn ~y:2020 ~m:Dec ~d:31 in let rec loop acc d = if (>) d stop_date then Result.ok_unit :: acc else begin let format_str = format d "%V" in let week_number_str = Printf.sprintf "%02i" (week_number d) in let result = if Core_kernel.Core_string.(<>) format_str week_number_str then Or_error.errorf "week_number for %s (%s) doesn't match output of (format \"%%V\") (%s)" (to_string d) week_number_str format_str else Result.ok_unit in loop (result :: acc) (add_days d 1) end in loop [] start_date |> Or_error.combine_errors_unit |> function | Result.Ok () -> () | Result.Error e -> Error.raise e ;; end core-113.00.00/src/date.mli000066400000000000000000000004461256461075500151720ustar00rootroot00000000000000type t = Date0.t include module type of Date0 with type t := t val of_time : Time.t -> zone:Zone.t -> t val today : zone:Zone.t -> t (** This formats a date using the format patterns available in [strftime]. Uses machine timezone where applicable. *) val format : t -> string -> string core-113.00.00/src/date0.ml000066400000000000000000000443771256461075500151140ustar00rootroot00000000000000open Core_kernel.Std open Time_internal.Helpers module Time = Time_internal.T let is_leap_year year = (year mod 4 = 0 && not (year mod 100 = 0)) || year mod 400 = 0 ;; (* Create a local private date type to ensure that all dates are created via Date.create_exn. *) module Stable = struct module V1 = struct module T : sig type t with bin_io val create_exn : y:int -> m:Month.Stable.V1.t -> d:int -> t val year : t -> int val month : t -> Month.Stable.V1.t val day : t -> int end = struct (* We used to store dates like this: type t = { y: int; m: Month.Stable.V1.t; d: int; } In the below we make sure that the bin_io representation is identical (and the stable unit tests check this) In memory we use the following much more compact representation: 2 bytes year 1 byte month 1 byte day all packed into a single immediate int (so from 4 words down to 1). *) type t = int let create0 ~year ~month ~day = (* create_exn's validation make sure that each value fits *) (year lsl 16) lor (Month.to_int month lsl 8) lor day ;; let year t = t lsr 16 let month t = Month.of_int_exn ((t lsr 8) land 0xff) let day t = t land 0xff TEST_UNIT = let test y m d = let t = create0 ~year:y ~month:m ~day:d in <:test_result< int >> ~expect:y (year t); <:test_result< Month.t >> ~expect:m (month t); <:test_result< int >> ~expect:d (day t); in test 2014 Month.Sep 24; test 9999 Month.Dec 31; ;; let create_exn ~y:year ~m:month ~d:day = let invalid msg = invalid_argf "Date.create_exn ~y:%d ~m:%s ~d:%d error: %s" year (Month.to_string month) day msg () in if year < 0 || year > 9999 then invalid "year outside of [0..9999]"; if day <= 0 then invalid "day <= 0"; begin match month with | Month.Apr | Month.Jun | Month.Sep | Month.Nov -> if day > 30 then invalid "30 day month violation" | Month.Feb -> if is_leap_year year then begin if day > 29 then invalid "29 day month violation" else () end else if day > 28 then begin invalid "28 day month violation" end else () | Month.Jan | Month.Mar | Month.May | Month.Jul | Month.Aug | Month.Oct | Month.Dec -> if day > 31 then invalid "31 day month violation" end; create0 ~year ~month:month ~day ;; (* We don't use Make_binable here, because that would go via an immediate tuple or record. That is exactly the 32 bytes we worked so hard above to get rid of. We also don't want to just bin_io the integer directly because that would mean a new bin_io format. *) let bin_read_t buf ~pos_ref = let year = Int.bin_read_t buf ~pos_ref in let month = Month.Stable.V1.bin_read_t buf ~pos_ref in let day = Int.bin_read_t buf ~pos_ref in create0 ~year ~month ~day ;; let __bin_read_t__ _buf ~pos_ref = (* __bin_read_t is only needed for variants *) Bin_prot.Common.raise_variant_wrong_type "Date.t" !pos_ref ;; let bin_reader_t = { Bin_prot.Type_class. read = bin_read_t; vtag_read = __bin_read_t__; } let bin_size_t t = Int.bin_size_t (year t) + Month.bin_size_t (month t) + Int.bin_size_t (day t) ;; let bin_write_t buf ~pos t = let pos = Int.bin_write_t buf ~pos (year t) in let pos = Month.bin_write_t buf ~pos (month t) in Int.bin_write_t buf ~pos (day t) ;; let bin_writer_t = { Bin_prot.Type_class. size = bin_size_t; write = bin_write_t; } let bin_t = { Bin_prot.Type_class. reader = bin_reader_t; writer = bin_writer_t; } end include T (** YYYY-MM-DD *) let to_string_iso8601_extended t = let buf = String.create 10 in blit_string_of_int_4_digits buf ~pos:0 (year t); buf.[4] <- '-'; blit_string_of_int_2_digits buf ~pos:5 (Month.to_int (month t)); buf.[7] <- '-'; blit_string_of_int_2_digits buf ~pos:8 (day t); buf ;; let to_string = to_string_iso8601_extended (** YYYYMMDD *) let to_string_iso8601_basic t = let buf = String.create 8 in blit_string_of_int_4_digits buf ~pos:0 (year t); blit_string_of_int_2_digits buf ~pos:4 (Month.to_int (month t)); blit_string_of_int_2_digits buf ~pos:6 (day t); buf ;; (** MM/DD/YYYY *) let to_string_american t = let buf = String.create 10 in blit_string_of_int_2_digits buf ~pos:0 (Month.to_int (month t)); buf.[2] <- '/'; blit_string_of_int_2_digits buf ~pos:3 (day t); buf.[5] <- '/'; blit_string_of_int_4_digits buf ~pos:6 (year t); buf ;; let parse_year4 str pos = parse_four_digits str pos let parse_month str pos = Month.of_int_exn (parse_two_digits str pos) let parse_day str pos = parse_two_digits str pos (** YYYYMMDD *) let of_string_iso8601_basic str ~pos = if pos + 8 > String.length str then invalid_arg "Date.of_string_iso8601_basic: pos + 8 > string length"; create_exn ~y:(parse_year4 str pos) ~m:(parse_month str (pos + 4)) ~d:(parse_day str (pos + 6)) ;; (* WARNING: if you are going to change this function in a material way, be sure you understand the implications of working in Stable *) let of_string s = let invalid () = failwith ("invalid date: " ^ s) in let ensure b = if not b then invalid () in let month_num ~year ~month ~day = create_exn ~y:(parse_year4 s year) ~m:(parse_month s month) ~d:(parse_day s day) in let month_abrv ~year ~month ~day = create_exn ~y:(parse_year4 s year) ~m:(Month.of_string (String.sub s ~pos:month ~len:3)) ~d:(parse_day s day) in if String.contains s '/' then begin let y,m,d = match String.split s ~on:'/' with | [a; b; c] -> if String.length a = 4 then a,b,c (* y/m/d *) else c,a,b (* m/d/y *) | _ -> invalid () in let year = Int.of_string y in let year = if year >= 100 then year else if year < 75 then 2000 + year else 1900 + year in let month = Month.of_int_exn (Int.of_string m) in let day = Int.of_string d in create_exn ~y:year ~m:month ~d:day end else if String.contains s '-' then begin (* yyyy-mm-dd *) ensure (String.length s = 10 && s.[4] = '-' && s.[7] = '-'); month_num ~year:0 ~month:5 ~day:8; end else if String.contains s ' ' then begin if (String.length s = 11 && s.[2] = ' ' && s.[6] = ' ') then (* DD MMM YYYY *) month_abrv ~day:0 ~month:3 ~year:7 else begin (* YYYY MMM DD *) ensure (String.length s = 11 && s.[4] = ' ' && s.[8] = ' '); month_abrv ~day:9 ~month:5 ~year:0; end end else if String.length s = 9 then begin (* DDMMMYYYY *) month_abrv ~day:0 ~month:2 ~year:5; end else if String.length s = 8 then begin (* assume YYYYMMDD *) month_num ~year:0 ~month:4 ~day:6 end else invalid () ;; let of_string s = try of_string s with | exn -> invalid_argf "Date.of_string (%s): %s" s (Exn.to_string exn) () ;; module Sexpable = struct module Old_date = struct type t = { y: int; m: int; d: int; } with sexp let to_date t = T.create_exn ~y:t.y ~m:(Month.of_int_exn t.m) ~d:t.d end let t_of_sexp = function | Sexp.Atom s -> of_string s | Sexp.List _ as sexp -> Old_date.to_date (Old_date.t_of_sexp sexp) ;; let t_of_sexp s = try t_of_sexp s with | (Sexplib.Conv.Of_sexp_error _) as exn -> raise exn | Invalid_argument a -> Sexplib.Conv.of_sexp_error a s ;; let sexp_of_t t = Sexp.Atom (to_string t) end include Sexpable module C = Comparable.Make_binable (struct include T include Sexpable include Binable let compare t1 t2 = let n = Int.compare (year t1) (year t2) in if n <> 0 then n else let n = Month.compare (month t1) (month t2) in if n <> 0 then n else Int.compare (day t1) (day t2) ;; end) include C module O = struct include (C : Comparable.Infix with type t := t) end end TEST_MODULE "Date.V1" = Core_kernel.Stable_unit_test.Make (struct include V1 let equal = (=) let tests = let date y m d = create_exn ~y ~m ~d in [ date 1066 Month.Oct 16, "1066-10-16", "\254\042\004\009\016"; date 1955 Month.Nov 5, "1955-11-05", "\254\163\007\010\005"; date 2012 Month.Apr 19, "2012-04-19", "\254\220\007\003\019"; ] end) end include Stable.V1 include (Hashable.Make_binable (struct include T include Sexpable include Binable let compare (a:t) (b:t) = compare a b let hash (t : t) = Hashtbl.hash t end) : Hashable.S_binable with type t := t) include Pretty_printer.Register (struct type nonrec t = t let module_name = "Core.Std.Date" let to_string = to_string end) let of_tm tm = create_exn ~y:(tm.Unix.tm_year + 1900) ~m:(Month.of_int_exn (tm.Unix.tm_mon + 1)) ~d:tm.Unix.tm_mday ;; (* The Days module is used for calculations that involve adding or removing a known number of days from a date. Internally the date is translated to a day number, the days are added, and the new date is returned. Those interested in the math can read: http://alcor.concordia.ca/~gpkatch/gdate-method.html note: unit tests are in lib_test/time_test.ml *) module Days : sig val add_days : t -> int -> t val diff : t -> t -> int end = struct open Int let of_year y = 365 * y + y / 4 - y / 100 + y / 400 let of_date date = let m = (Month.to_int (month date) + 9) % 12 in let y = (year date) - m / 10 in of_year y + (m * 306 + 5) / 10 + ((day date) - 1) ;; let c_10_000 = Int63.of_int 10_000 let c_14_780 = Int63.of_int 14_780 let c_3_652_425 = Int63.of_int 3_652_425 let to_date days = let y = let open Int63 in to_int_exn ((c_10_000 * of_int days + c_14_780) / c_3_652_425) in let ddd = days - of_year y in let y, ddd = if (ddd < 0) then let y = y - 1 in (y, days - of_year y) else (y, ddd) in let mi = (100 * ddd + 52) / 3_060 in let y = y + (mi + 2) / 12 in let m = (mi + 2) % 12 + 1 in let d = ddd - (mi * 306 + 5) / 10 + 1 in create_exn ~y ~m:(Month.of_int_exn m) ~d ;; let add_days t days = to_date (of_date t + days) let diff t1 t2 = of_date t1 - of_date t2 end let add_days = Days.add_days let diff = Days.diff let add_months t n = let total_months = (Month.to_int (month t)) + n in let y = (year t) + (total_months /% 12) in let m = total_months % 12 in (** correct for december **) let (y, m) = if Int.(=) m 0 then (y - 1, m + 12) else (y, m) in let m = Month.of_int_exn m in (** handle invalid dates for months with fewer number of days **) let rec try_create d = try create_exn ~y ~m ~d with _exn -> assert (Int.(>=) d 1); try_create (d - 1) in try_create (day t) ;; (* http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week#Purely_mathematical_methods note: unit tests in lib_test/time_test.ml *) let day_of_week = let table = [| 0; 3; 2; 5; 0; 3; 5; 1; 4; 6; 2; 4 |] in (fun t -> let m = Month.to_int (month t) in let y = if Int.(<) m 3 then (year t) - 1 else (year t) in Day_of_week.of_int_exn ((y + y / 4 - y / 100 + y / 400 + table.(m - 1) + (day t)) % 7)) ;; (* http://en.wikipedia.org/wiki/Ordinal_date *) let non_leap_year_table = [| 0; 31; 59; 90; 120; 151; 181; 212; 243; 273; 304; 334 |] let leap_year_table = [| 0; 31; 60; 91; 121; 152; 182; 213; 244; 274; 305; 335 |] let ordinal_date t = let table = if is_leap_year (year t) then leap_year_table else non_leap_year_table in let offset = table.(Month.to_int (month t) - 1) in day t + offset ;; let last_week_of_year y = let first_of_year = create_exn ~y ~m:Jan ~d:1 in let is t day = Day_of_week.equal (day_of_week t) day in if is first_of_year Thu || (is_leap_year y && is first_of_year Wed) then 53 else 52 ;; (* See http://en.wikipedia.org/wiki/ISO_week_date or ISO 8601 for the details of this algorithm. *) let week_number t = let ordinal = ordinal_date t in let weekday = Day_of_week.iso_8601_weekday_number (day_of_week t) in (* [ordinal - weekday + 4] is the ordinal of this week's Thursday, then (n + 6) / 7 is division by 7 rounding up *) let week = (ordinal - weekday + 10) / 7 in let year = year t in if Int.(<) week 1 then last_week_of_year (year - 1) else begin if Int.(>) week (last_week_of_year year) then 1 else week end ;; (* Illustrative examples. See date.ml for some more exhaustive tests. *) TEST_MODULE "week_number" = struct TEST_UNIT = <:test_result< int >> (ordinal_date (create_exn ~y:2014 ~m:Jan ~d:1)) ~expect:1 TEST_UNIT = <:test_result< int >> (ordinal_date (create_exn ~y:2014 ~m:Dec ~d:31)) ~expect:365 TEST_UNIT = <:test_result< int >> (ordinal_date (create_exn ~y:2014 ~m:Feb ~d:28)) ~expect:59 let test_week_number y m d ~expect = <:test_result< int >> (week_number (create_exn ~y ~m ~d)) ~expect TEST_UNIT = test_week_number 2014 Jan 1 ~expect:1 TEST_UNIT = test_week_number 2014 Dec 31 ~expect:1 TEST_UNIT = test_week_number 2010 Jan 1 ~expect:53 TEST_UNIT = test_week_number 2017 Jan 1 ~expect:52 TEST_UNIT = test_week_number 2014 Jan 10 ~expect:2 TEST_UNIT = test_week_number 2012 Jan 1 ~expect:52 TEST_UNIT = test_week_number 2012 Dec 31 ~expect:1 end let is_weekend t = Day_of_week.is_sun_or_sat (day_of_week t) ;; let is_weekday t = not (is_weekend t) let is_business_day t ~is_holiday = is_weekday t && not (is_holiday t) ;; let add_days_skipping t ~skip n = let step = if Int.(>=) n 0 then 1 else -1 in let rec loop t k = let t_next = add_days t step in if skip t then loop t_next k else if Int.(=) k 0 then t else loop t_next (k - 1) in loop t (abs n) let add_weekdays t n = add_days_skipping t ~skip:is_weekend n let add_business_days t ~is_holiday n = add_days_skipping t n ~skip:(fun d -> is_weekend d || is_holiday d) ;; let dates_between ~min:t1 ~max:t2 = let rec loop t l = if t < t1 then l else loop (add_days t (-1)) (t::l) in loop t2 [] ;; TEST_MODULE "ordinal_date" = struct (* check the ordinal date tables we found on wikipedia... *) let check_table year ordinal_date_table = let days_of_year = dates_between ~min:(create_exn ~y:year ~m:Month.Jan ~d:01) ~max:(create_exn ~y:year ~m:Month.Dec ~d:31) in <:test_result> (List.length days_of_year) ~expect:(if is_leap_year year then 366 else 365); let months = List.group days_of_year ~break:(fun d d' -> Month.(<>) (month d) (month d')) in let sum = List.foldi months ~init:0 ~f:(fun index sum month -> <:test_result< int >> sum ~expect:ordinal_date_table.(index); sum + List.length month) in <:test_result< int >> sum ~expect:(List.length days_of_year) ;; TEST_UNIT = check_table 2015 non_leap_year_table TEST_UNIT = check_table 2000 leap_year_table end let weekdays_between ~min ~max = let all_dates = dates_between ~min ~max in Option.value_map (List.hd all_dates) ~default:[] ~f:(fun first_date -> (* to avoid a system call on every date, we just get the weekday for the first date and use it to get all the other weekdays *) let first_weekday = day_of_week first_date in let date_and_weekdays = List.mapi all_dates ~f:(fun i date -> date,Day_of_week.shift first_weekday i) in List.filter_map date_and_weekdays ~f:(fun (date,weekday) -> if Day_of_week.is_sun_or_sat weekday then None else Some date) ) ;; let business_dates_between ~min ~max ~is_holiday = weekdays_between ~min ~max |! List.filter ~f:(fun d -> not (is_holiday d)) ;; let rec previous_weekday t = let previous_day = add_days t (-1) in if is_weekday previous_day then previous_day else previous_weekday previous_day ;; let rec following_weekday t = let following_day = add_days t 1 in if is_weekday following_day then following_day else following_weekday following_day ;; let first_strictly_after t ~on:dow = let dow = Day_of_week.to_int dow in let tplus1 = add_days t 1 in let cur = Day_of_week.to_int (day_of_week tplus1) in let diff = (dow + 7 - cur) mod 7 in add_days tplus1 diff ;; TEST_MODULE "first_strictly_after" = struct let mon1 = create_exn ~y:2013 ~m:Month.Apr ~d:1 let tue1 = create_exn ~y:2013 ~m:Month.Apr ~d:2 let wed1 = create_exn ~y:2013 ~m:Month.Apr ~d:3 let thu1 = create_exn ~y:2013 ~m:Month.Apr ~d:4 let fri1 = create_exn ~y:2013 ~m:Month.Apr ~d:5 let sat1 = create_exn ~y:2013 ~m:Month.Apr ~d:6 let sun1 = create_exn ~y:2013 ~m:Month.Apr ~d:7 let mon2 = create_exn ~y:2013 ~m:Month.Apr ~d:8 let tue2 = create_exn ~y:2013 ~m:Month.Apr ~d:9 TEST = equal (first_strictly_after tue1 ~on:Day_of_week.Mon) mon2 TEST = equal (first_strictly_after tue1 ~on:Day_of_week.Tue) tue2 TEST = equal (first_strictly_after tue1 ~on:Day_of_week.Wed) wed1 TEST = equal (first_strictly_after tue1 ~on:Day_of_week.Thu) thu1 TEST = equal (first_strictly_after tue1 ~on:Day_of_week.Fri) fri1 TEST = equal (first_strictly_after tue1 ~on:Day_of_week.Sat) sat1 TEST = equal (first_strictly_after tue1 ~on:Day_of_week.Sun) sun1 TEST = equal (first_strictly_after mon1 ~on:Day_of_week.Mon) mon2 TEST = equal (first_strictly_after mon1 ~on:Day_of_week.Tue) tue1 TEST = equal (first_strictly_after mon1 ~on:Day_of_week.Wed) wed1 TEST = equal (first_strictly_after mon1 ~on:Day_of_week.Thu) thu1 TEST = equal (first_strictly_after mon1 ~on:Day_of_week.Fri) fri1 TEST = equal (first_strictly_after mon1 ~on:Day_of_week.Sat) sat1 TEST = equal (first_strictly_after mon1 ~on:Day_of_week.Sun) sun1 end core-113.00.00/src/date0.mli000066400000000000000000000075441256461075500152600ustar00rootroot00000000000000open Core_kernel.Std type t with bin_io, sexp include Hashable_binable with type t := t (** converts a string to a date, in formats: * m/d/y * y-m-d (* valid iso8601_extended *) * DD MMM YYYY * DDMMMYYYY * YYYYMMDD *) include Stringable with type t := t include Comparable_binable with type t := t include Pretty_printer.S with type t := t (** [create_exn ~y ~m ~d] creates the date specified in the arguments. Arguments are validated, and are not normalized in any way. So, days must be within the limits for the month in question, numbers cannot be negative, years must be fully specified, etc. *) val create_exn : y:int -> m:Month.t -> d:int -> t val of_tm : Core_unix.tm -> t (* For details on this ISO format, see: http://www.wikipedia.org/wiki/iso8601 *) val of_string_iso8601_basic : string -> pos:int -> t (* YYYYMMDD *) val to_string_iso8601_basic : t -> string (* YYYYMMDD *) val to_string_american : t -> string (* MM/DD/YYYY *) val day : t -> int val month : t -> Month.t val year : t -> int val day_of_week : t -> Day_of_week.t (** Week of the year, from 1 to 53. According to ISO 8601, weeks start on Monday, and the first week of a year is the week that contains the first Thursday of the year. Notice that this means that dates near the end of the year can have week number 1, and dates near the beginning of the year can have week number 52 or 53. Warning: the triple (year, week number, week day) does not identify a date -- e.g. 2012-01-02 and 2012-12-31 are both Mondays of week 1. (However, if instead of the year, you use the year of the nearest Thursday, then it does work.) *) val week_number : t -> int val is_weekend : t -> bool val is_weekday : t -> bool (** Monday through Friday are business days, unless they're a holiday. Use [Pnl_db.Holidays.is_holiday] as a convenient holiday function. *) val is_business_day : t -> is_holiday:(t -> bool) -> bool (* [add_days t n] adds n days to [t] and returns the resulting date. *) val add_days : t -> int -> t (** [add_months t n] returns date with max days for the month if the date would be invalid. e.g. adding 1 month to Jan 30 results in Feb 28 due to Feb 30 being an invalid date, Feb 29 is returned in cases of leap year. **) val add_months : t -> int -> t (** [diff t1 t2] returns date [t1] minus date [t2] in days. *) val diff : t -> t -> int (** [add_weekdays t 0] returns the next weekday if [t] is a weekend and [t] otherwise. Unlike add_days this is done by looping over the count of days to be added (forward or backwards based on the sign), and is O(n) in the number of days to add. Beware, [add_weekdays sat 1] or [add_weekdays sun 1] both return the next [tue], not the next [mon]. You may want to use [following_weekday] if you want the next following weekday, [following_weekday (fri|sat|sun)] would all return the next [mon]. *) val add_weekdays : t -> int -> t (** [add_business_days t ~is_holiday n] returns a business day even when [n=0]. [add_business_days ~is_holiday:(fun _ -> false) ...] is the same as [add_weekdays]. Use [Pnl_db.Holidays.is_holiday] as a convenient holiday function. *) val add_business_days : t -> is_holiday:(t -> bool) -> int -> t (* the following returns a closed interval (endpoints included) *) val dates_between : min:t -> max:t -> t list val business_dates_between : min:t -> max:t -> is_holiday:(t -> bool) -> t list val weekdays_between : min:t -> max:t -> t list val previous_weekday : t -> t val following_weekday : t -> t (** [first_strictly_after t ~on:day_of_week] returns the first occurrence of [day_of_week] strictly after [t]. *) val first_strictly_after : t -> on:Day_of_week.t -> t module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io, compare end end module O : sig include Comparable.Infix with type t := t end core-113.00.00/src/day_of_week.ml000066400000000000000000000000401256461075500163460ustar00rootroot00000000000000include Core_kernel.Day_of_week core-113.00.00/src/debug.ml000066400000000000000000000016711256461075500151730ustar00rootroot00000000000000open Core_kernel.Std include Core_kernel.Debug let should_print_backtrace = ref false let am_internal here message = (* In this function we use [Printf.eprintf] rather than [Debug.eprintf], because the former doesn't flush, while the latter does. We'd rather flush once at the end, rather than three times. *) Printf.eprintf "%s:\n" (Source_code_position.to_string here); if !should_print_backtrace then Printf.eprintf "%s\n" (Backtrace.get () |> <:sexp_of< Backtrace.t >> |> Sexp.to_string_hum); begin match message with | None -> () | Some message -> Printf.eprintf "%s\n" message; end; Printf.eprintf "%!"; ;; let am here = am_internal here None let amf here fmt = ksprintf (fun string -> am_internal here (Some string)) fmt let ams here message a sexp_of_a = am_internal here (Some ((message, a) |> <:sexp_of< string * a >> |> Sexp.to_string_hum)) ;; core-113.00.00/src/debug.mli000066400000000000000000000021071256461075500153370ustar00rootroot00000000000000open Core_kernel.Std include module type of Core_kernel.Debug (** [am], [ams], and [amf] output a source code position and backtrace to stderr. [amf] accepts a printf-style format string. [ams] accepts a message, value, and sexp converter for that value. Typical usage looks like: {[ ...; Debug.am _here_; ...; Debug.amf _here_ "hello (%s, %s)" (X.to_string x) (Y.to_string y); ...; Debug.ams _here_ "hello" (x, y) <:sexp_of< X.t * Y.t >>; ...; ]} The [am*] functions output source code positions in the standard format "FILE:LINE:COL", which means that one can use a tool like emacs grep-mode on a buffer containing debug messages to step through one's code by stepping through the messages. *) val am : Source_code_position.t -> unit val ams : Source_code_position.t -> string -> 'a -> ('a -> Sexp.t) -> unit val amf : Source_code_position.t -> ('r, unit, string, unit) format4 -> 'r (** [should_print_backtrace] governs whether the [am*] functions print a backtrace. *) val should_print_backtrace : bool ref core-113.00.00/src/dequeue.ml000066400000000000000000000000341256461075500155320ustar00rootroot00000000000000include Core_kernel.Dequeue core-113.00.00/src/doubly_linked.ml000066400000000000000000000000421256461075500167200ustar00rootroot00000000000000include Core_kernel.Doubly_linked core-113.00.00/src/equal.ml000066400000000000000000000000321256461075500152020ustar00rootroot00000000000000include Core_kernel.Equal core-113.00.00/src/error.ml000066400000000000000000000000321256461075500152240ustar00rootroot00000000000000include Core_kernel.Error core-113.00.00/src/exn.ml000066400000000000000000000000301256461075500146630ustar00rootroot00000000000000include Core_kernel.Exn core-113.00.00/src/flags.ml000066400000000000000000000000321256461075500151670ustar00rootroot00000000000000include Core_kernel.Flags core-113.00.00/src/flags_intf.ml000066400000000000000000000000371256461075500162140ustar00rootroot00000000000000include Core_kernel.Flags_intf core-113.00.00/src/float.ml000066400000000000000000000000321256461075500152000ustar00rootroot00000000000000include Core_kernel.Float core-113.00.00/src/float_intf.ml000066400000000000000000000000371256461075500162250ustar00rootroot00000000000000include Core_kernel.Float_intf core-113.00.00/src/float_robust_compare.ml000066400000000000000000000000511256461075500203050ustar00rootroot00000000000000include Core_kernel.Float_robust_compare core-113.00.00/src/floatable.ml000066400000000000000000000000361256461075500160300ustar00rootroot00000000000000include Core_kernel.Floatable core-113.00.00/src/fn.ml000066400000000000000000000000271256461075500145020ustar00rootroot00000000000000include Core_kernel.Fn core-113.00.00/src/force_once.ml000066400000000000000000000000371256461075500162020ustar00rootroot00000000000000include Core_kernel.Force_once core-113.00.00/src/fqueue.ml000066400000000000000000000000331256461075500153660ustar00rootroot00000000000000include Core_kernel.Fqueue core-113.00.00/src/hash_heap.ml000066400000000000000000000000361256461075500160170ustar00rootroot00000000000000include Core_kernel.Hash_heap core-113.00.00/src/hash_queue.ml000066400000000000000000000000371256461075500162270ustar00rootroot00000000000000include Core_kernel.Hash_queue core-113.00.00/src/hash_set.ml000066400000000000000000000000351256461075500156740ustar00rootroot00000000000000include Core_kernel.Hash_set core-113.00.00/src/hash_set_intf.ml000066400000000000000000000000421256461075500167120ustar00rootroot00000000000000include Core_kernel.Hash_set_intf core-113.00.00/src/hashable.ml000066400000000000000000000000351256461075500156450ustar00rootroot00000000000000include Core_kernel.Hashable core-113.00.00/src/heap.ml000066400000000000000000000000311256461075500150070ustar00rootroot00000000000000include Core_kernel.Heap core-113.00.00/src/heap_block.ml000066400000000000000000000000371256461075500161670ustar00rootroot00000000000000include Core_kernel.Heap_block core-113.00.00/src/host_and_port.ml000066400000000000000000000000421256461075500167370ustar00rootroot00000000000000include Core_kernel.Host_and_port core-113.00.00/src/identifiable.ml000066400000000000000000000000411256461075500165120ustar00rootroot00000000000000include Core_kernel.Identifiable core-113.00.00/src/in_channel.ml000066400000000000000000000000371256461075500161760ustar00rootroot00000000000000include Core_kernel.In_channel core-113.00.00/src/includes.h000066400000000000000000000001051256461075500155210ustar00rootroot00000000000000#include #include #undef unix #undef linux core-113.00.00/src/info.ml000066400000000000000000000000311256461075500150250ustar00rootroot00000000000000include Core_kernel.Info core-113.00.00/src/int_conversions.ml000066400000000000000000000000441256461075500173200ustar00rootroot00000000000000include Core_kernel.Int_conversions core-113.00.00/src/int_intf.ml000066400000000000000000000000351256461075500157100ustar00rootroot00000000000000include Core_kernel.Int_intf core-113.00.00/src/int_replace_polymorphic_compare.ml000066400000000000000000000000641256461075500225200ustar00rootroot00000000000000include Core_kernel.Int_replace_polymorphic_compare core-113.00.00/src/int_set.ml000066400000000000000000000000341256461075500155420ustar00rootroot00000000000000include Core_kernel.Int_set core-113.00.00/src/intable.ml000066400000000000000000000000341256461075500155130ustar00rootroot00000000000000include Core_kernel.Intable core-113.00.00/src/interfaces.ml000066400000000000000000000000371256461075500162230ustar00rootroot00000000000000include Core_kernel.Interfaces core-113.00.00/src/interval.ml000066400000000000000000000323571256461075500157360ustar00rootroot00000000000000 open Core_kernel.Std open Int.Replace_polymorphic_compare let _ = (=) (* turns off the unused open warning *) module Stable = struct module V1 = struct module T = struct type 'a t = | Interval of 'a * 'a | Empty with bin_io, of_sexp, variants, compare type 'a interval = 'a t with bin_io, of_sexp, compare let interval_of_sexp a_of_sexp sexp = try interval_of_sexp a_of_sexp sexp (* for backwards compatibility *) with _exn -> match sexp with | Sexp.List [] -> Empty | Sexp.List [ lb; ub ] -> Interval (a_of_sexp lb, a_of_sexp ub) | Sexp.Atom _ | Sexp.List _ -> of_sexp_error "Interval.t_of_sexp: expected pair or empty list" sexp let sexp_of_interval sexp_of_a t = match t with | Empty -> Sexp.List [] | Interval (lb, ub) -> Sexp.List [ sexp_of_a lb; sexp_of_a ub ] end open T module Float = struct type t = float interval with sexp, bin_io, compare end module Int = struct type t = int interval with sexp, bin_io, compare end module Time = struct type t = Time.Stable.V1.t interval with sexp, bin_io, compare end module Ofday = struct type t = Ofday.Stable.V1.t interval with sexp, bin_io, compare end end let make_tests_v1 ~non_empty = let module V = Variantslib.Variant in let c f tests variant = (f variant) @ tests in V1.T.Variants.fold ~init:[] ~interval:(c (fun interval -> assert (interval.V.rank = 0); List.map non_empty ~f:(fun ((lbound, ubound), sexp, bin_io) -> interval.V.constructor lbound ubound, sexp, bin_io))) ~empty:(c (fun empty -> assert (empty.V.rank = 1); [ empty.V.constructor, "()", "\001" ])) TEST_MODULE "Interval.V1.Float" = Core_kernel.Stable_unit_test.Make(struct include V1.Float let equal x1 x2 = (V1.T.compare Float.compare x1 x2) = 0 module V = V1.T.Variants let tests = make_tests_v1 ~non_empty: [ (1.5, 120.), "(1.5 120)", "\000\000\000\000\000\000\000\248?\000\000\000\000\000\000^@" ] end) TEST_MODULE "Interval.V1.Int" = Core_kernel.Stable_unit_test.Make(struct include V1.Int let equal x1 x2 = (V1.T.compare Int.compare x1 x2) = 0 module V = V1.T.Variants let tests = make_tests_v1 ~non_empty: [ (-5, 789), "(-5 789)", "\000\255\251\254\021\003" ] end) TEST_MODULE "Interval.V1.Time" = struct module Arg = struct include V1.Time let equal x1 x2 = (V1.T.compare Time.compare x1 x2) = 0 let zone = Zone.of_string "America/New_York" module V = V1.T.Variants let tests = let t1 = Time.of_date_ofday ~zone (Date.create_exn ~y:2013 ~m:Month.Aug ~d:6) (Ofday.create ~hr:7 ~min:30 ~sec:7 ~ms:12 ~us:5 ()) in let t2 = Time.of_date_ofday ~zone (Date.create_exn ~y:2014 ~m:Month.Sep ~d:8) (Ofday.create ~hr:10 ~min:10 ~sec:0 ~ms:22 ~us:0 ()) in make_tests_v1 ~non_empty: [ (t1, t2), "((2013-08-06 07:30:07.012005-04:00) (2014-09-08 10:10:00.022000-04:00))", "\000\177\196\192\1437\128\212Ash\001.n\003\213A" ] end (* Bypass sexp serialization tests because [Time.sexp_of_t] gives different results depending on the local zone. *) include Core_kernel.Stable_unit_test.Make_sexp_deserialization_test(Arg) include Core_kernel.Stable_unit_test.Make_bin_io_test(Arg) end TEST_MODULE "Interval.V1.Ofday" = Core_kernel.Stable_unit_test.Make(struct include V1.Ofday let equal x1 x2 = (V1.T.compare Ofday.compare x1 x2) = 0 module V = V1.T.Variants let tests = let t1 = Ofday.create ~hr:7 ~min:30 ~sec:7 ~ms:12 ~us:5 () in let t2 = Ofday.create ~hr:9 ~min:45 ~sec:8 ~ms:0 ~us:1 () in make_tests_v1 ~non_empty: [ (t1, t2) , "(07:30:07.012005 09:45:08.000001)", "\000\153\158\176\196\192_\218@\223\024\002\000\128$\225@" ] end) end open Stable.V1.T module type Bound = sig type 'a bound val compare : 'a bound -> 'a bound -> int val ( >= ) : 'a bound -> 'a bound -> bool val ( <= ) : 'a bound -> 'a bound -> bool val ( = ) : 'a bound -> 'a bound -> bool val ( > ) : 'a bound -> 'a bound -> bool val ( < ) : 'a bound -> 'a bound -> bool val ( <> ) : 'a bound -> 'a bound -> bool end module Raw_make (T : Bound) = struct module T = struct include T let _ = ( <> ) (* Prevent unused value warning for "<>" *) let max x y = if T.(>=) x y then x else y let min x y = if T.(<=) x y then x else y end module Interval = struct let empty = Empty let is_malformed = function | Empty -> false | Interval (x,y) -> T.(>) x y let empty_cvt = function | Empty -> Empty | Interval (x,y) as i -> if T.(>) x y then Empty else i let create x y = (* if x > y, then this is just the Empty interval. *) empty_cvt (Interval (x,y)) let intersect i1 i2 = match i1,i2 with | Empty,_ | _,Empty -> Empty | Interval (l1,u1), Interval (l2,u2) -> empty_cvt (Interval (T.max l1 l2, T.min u1 u2)) let is_empty = function Empty -> true | _ -> false let is_empty_or_singleton = function | Empty -> true | Interval (x,y) -> T.(=) x y let bounds = function Empty -> None | Interval (l, u) -> Some (l,u) let lbound = function Empty -> None | Interval (l, _) -> Some l let ubound = function Empty -> None | Interval (_, u) -> Some u let bounds_exn = function | Empty -> invalid_arg "Interval.bounds_exn: empty interval" | Interval (l,u) -> (l,u) let lbound_exn = function | Empty -> invalid_arg "Interval.lbound_exn: empty interval" | Interval (l,_) -> l let ubound_exn = function | Empty -> invalid_arg "Interval.ubound_exn: empty interval" | Interval (_,u) -> u let compare_value i x = match i with | Empty -> `Interval_is_empty | Interval (l,u) -> if T.(<) x l then `Below else if T.(>) x u then `Above else `Within let contains i x = Pervasives.(=) (compare_value i x) `Within let bound i x = match i with | Empty -> None | Interval (l,u) -> let bounded_value = if T.(<) x l then l else if T.(<) u x then u else x in Some bounded_value let is_superset i1 ~of_:i2 = match i1,i2 with | Interval (l1,u1), Interval (l2,u2) -> T.(<=) l1 l2 && T.(>=) u1 u2 | _, Empty -> true | Empty, Interval (_, _) -> false let is_subset i1 ~of_:i2 = is_superset i2 ~of_:i1 let map t ~f = match t with | Empty -> Empty | Interval (l,u) -> empty_cvt (Interval (f l, f u)) ;; let interval_compare t1 t2 = match t1, t2 with | Empty, Empty -> 0 | Empty, Interval _ -> -1 | Interval _, Empty -> 1 | Interval (l1,u1), Interval (l2,u2) -> let c = T.compare l1 l2 in if Int.(<>) c 0 then c else T.compare u1 u2 ;; let are_disjoint_gen ~are_disjoint intervals = let intervals = Array.of_list intervals in try for i = 0 to Array.length intervals - 1 do for j = i + 1 to Array.length intervals - 1 do if not (are_disjoint intervals.(i) intervals.(j)) then raise Exit done done; true with Exit -> false let are_disjoint intervals = are_disjoint_gen intervals ~are_disjoint:(fun i1 i2 -> is_empty (intersect i1 i2)) let are_disjoint_as_open_intervals intervals = are_disjoint_gen intervals ~are_disjoint:(fun i1 i2 -> is_empty_or_singleton (intersect i1 i2)) let list_intersect ilist1 ilist2 = if not (are_disjoint ilist1) || not (are_disjoint ilist2) then invalid_arg "Interval.list_intersect: non-disjoint input list"; let pairs = List.cartesian_product ilist1 ilist2 in List.filter_map pairs ~f:(fun (i1,i2) -> let i = intersect i1 i2 in if is_empty i then None else Some i) let half_open_intervals_are_a_partition intervals = let intervals = List.filter ~f:(fun x -> not (is_empty x)) intervals in let intervals = List.sort ~cmp:interval_compare intervals in (* requires sorted list of intervals *) let rec is_partition a = function | [] -> true | b :: tl -> T.(=) (ubound_exn a) (lbound_exn b) && is_partition b tl in match intervals with | [] -> true | x::xs -> is_partition x xs let convex_hull intervals = List.fold intervals ~init:empty ~f:(fun i1 i2 -> (* Compute the convex hull of two intervals *) match bounds i1, bounds i2 with | None, _ -> i2 | _ , None -> i1 | Some (l1,u1), Some (l2,u2) -> create (T.min l1 l2) (T.max u1 u2)) end module Set = struct let create_from_intervals intervals = let intervals = List.filter intervals ~f:(fun i -> not (Interval.is_empty i)) in let intervals = let lb i = Interval.lbound_exn i in List.sort intervals ~cmp:(fun i i' -> T.compare (lb i) (lb i')) in if not (Interval.are_disjoint intervals) then failwith "Interval_set.create: intervals were not disjoint" else intervals ;; let create pair_list = let intervals = List.map pair_list ~f:(fun (lbound, ubound) -> Interval.create lbound ubound) in create_from_intervals intervals ;; let contains_set ~container ~contained = List.for_all contained ~f:(fun contained_interval -> List.exists container ~f:(fun container_interval -> Interval.is_superset container_interval ~of_:contained_interval ) ) let contains t x = List.exists t ~f:(fun interval -> Interval.contains interval x) let ubound_exn t = match t with | [] -> invalid_arg "Interval_set.ubound called on empty set" | _ -> Interval.ubound_exn (List.last_exn t) let lbound_exn t = match t with | [] -> invalid_arg "Interval_set.lbound called on empty set" | _ -> Interval.lbound_exn (List.hd_exn t) let ubound t = match List.last t with | None -> None | Some i -> match Interval.ubound i with | None -> assert false | Some x -> Some x let lbound t = match List.hd t with | None -> None | Some i -> match Interval.lbound i with | None -> assert false | Some x -> Some x end end type 'a t = 'a interval with bin_io, sexp type 'a bound_ = 'a module C = Raw_make (struct type 'a bound = 'a include Pervasives end) include C.Interval let t_of_sexp a_of_sexp s = let t = t_of_sexp a_of_sexp s in if is_malformed t then Sexplib.Conv.of_sexp_error "Interval.t_of_sexp error: malformed input" s; t ;; module Set = struct type 'a t = 'a interval list with bin_io, sexp include C.Set end module Make (Bound : sig type t with bin_io, sexp include Comparable.S with type t := t end) = struct type t = Bound.t interval with bin_io, sexp type 'a t_ = t type interval = t with bin_io, sexp type bound = Bound.t type 'a bound_ = bound module C = Raw_make (struct type 'a bound = Bound.t let compare = Bound.compare include (Bound : Comparable.Infix with type t := Bound.t) end) include C.Interval let to_poly (t : t) = t let t_of_sexp s = let t = t_of_sexp s in if is_malformed t then failwithf "Interval.Make.t_of_sexp error: malformed input %s" (Sexp.to_string s) () else t ;; module Set = struct type t = interval list with sexp, bin_io type 'a t_ = t include C.Set let to_poly (t : t) = t end end module type S1 = Interval_intf.S1 module type S = Interval_intf.S with type 'a poly_t := 'a t with type 'a poly_set := 'a Set.t module Float = Make (Float) module Int = Make (Int ) module Ofday = Make (Ofday) (* Tests for list bound functions *) TEST_MODULE = struct let intervals = [ Int.empty ; Interval (3, 6) ; Interval (2, 7) ; Int.empty ; Interval (4, 5)] TEST = match Int.convex_hull intervals with | Interval (2, 7) -> true | _ -> false let intervals = [ Int.empty ; Interval (3, 6) ; Interval (2, 3) ; Int.empty ; Interval (4, 5)] TEST = match Int.convex_hull intervals with | Interval (2, 6) -> true | _ -> false let intervals = [ Int.empty ; Int.empty] TEST = match Int.convex_hull intervals with | Empty -> true | _ -> false end module Time = struct include Make(Time) let create_ending_after ?(zone = Zone.local) (open_ofday, close_ofday) ~now = let close_time = Time.occurrence `First_after_or_at now ~zone ~ofday:close_ofday in let open_time = Time.occurrence `Last_before_or_at close_time ~zone ~ofday:open_ofday in create open_time close_time let create_ending_before ?(zone = Zone.local) (open_ofday, close_ofday) ~ubound = let close_time = Time.occurrence `Last_before_or_at ubound ~zone ~ofday:close_ofday in let open_time = Time.occurrence `Last_before_or_at close_time ~zone ~ofday:open_ofday in create open_time close_time end core-113.00.00/src/interval.mli000066400000000000000000000037571256461075500161110ustar00rootroot00000000000000(** Module for simple closed intervals over arbitrary types that are ordered correctly using polymorphic compare. *) open Core_kernel.Std open Interval_intf module type S1 = S1 (* Sexps are () for empty interval and (3 5) for an interval containing 3, 4, and 5. *) include S1 module type S = S with type 'a poly_t := 'a t with type 'a poly_set := 'a Set.t module Make (Bound : sig type t with bin_io, sexp include Comparable.S with type t := t end) : S with type bound = Bound.t module Float : S with type bound = Float.t module Int : S with type bound = Int.t module Time : sig include S with type bound = Time.t (** [create_ending_after ?zone (od1, od2) ~now] returns the smallest interval [(t1 t2)] with minimum [t2] such that [t2 >= now], [to_ofday t1 = od1], and [to_ofday t2 = od2]. If zone is specified, it is used to translate od1 and od2 into times, otherwise the machine's time zone is used. It is not guaranteed that [contains (t1 t2) now], which will be false iff there is no interval containing [now] with [to_ofday t1 = od1] and [to_ofday t2 = od1] . *) val create_ending_after : ?zone:Zone.t -> Ofday.t * Ofday.t -> now:Time.t -> t (** [create_ending_before ?zone (od1, od2) ~ubound] returns the smallest interval [(t1 t2)] with maximum [t2] such that [t2 <= ubound], [to_ofday t1 = od1], and [to_ofday t2 = od2]. If zone is specified, it is used to translate od1 and od2 into times, otherwise the machine's time zone is used. *) val create_ending_before : ?zone:Zone.t -> Ofday.t * Ofday.t -> ubound:Time.t -> t end (* The spec for [Ofday] must be below the spec for [Time], so as not to shadow the uses of [Ofday] in the spec for [Time]. *) module Ofday : S with type bound = Ofday.t module Stable : sig module V1 : sig module Float : Stable with type t = Float.t module Int : Stable with type t = Int. t module Time : Stable with type t = Time. t module Ofday : Stable with type t = Ofday.t end end core-113.00.00/src/interval_intf.ml000066400000000000000000000125141256461075500167470ustar00rootroot00000000000000module type Gen = sig type 'a t (* [bound] is the type of points in the interval (and also of the bounds, which are points; hence the name). [bound] is instantiated in two different ways below: in [module type S] as a monotype and in [module type S1] as ['a]. *) type 'a bound (** Module for simple closed intervals over arbitrary types that are ordered correctly using polymorphic compare. *) (** [create l u] returns the interval with lower bound [l] and upper bound [u], unless [l > u], in which case [create] returns the empty interval. *) val create : 'a bound -> 'a bound -> 'a t val empty : 'a t val intersect : 'a t -> 'a t -> 'a t val is_empty : 'a t -> bool val is_empty_or_singleton : 'a t -> bool val bounds : 'a t -> ('a bound * 'a bound) option val lbound : 'a t -> 'a bound option val ubound : 'a t -> 'a bound option val bounds_exn : 'a t -> ('a bound * 'a bound) val lbound_exn : 'a t -> 'a bound val ubound_exn : 'a t -> 'a bound (** [convex_hull ts] returns an interval whose upperbound is the greatest upperbound of the intervals in the list, and whose lowerbound is the least lowerbound of the list. *) val convex_hull : 'a t list -> 'a t val contains : 'a t -> 'a bound -> bool val compare_value : 'a t -> 'a bound -> [ `Below | `Within | `Above | `Interval_is_empty ] (** [bound t x] returns [None] iff [is_empty t]. If [bounds t = Some (a, b)], then [bound] returns [Some y] where [y] is the element of [t] closest to [x]. I.e.: | y = a if x < a | y = x if a <= x <= b | y = b if x > b *) val bound : 'a t -> 'a bound -> 'a bound option (** [is_superset i1 of_:i2] is whether i1 contains i2. The empty interval is contained in every interval. *) val is_superset : 'a t -> of_:'a t -> bool val is_subset : 'a t -> of_:'a t -> bool (** [map t ~f] returns [create (f l) (f u)] if [bounds t = Some (l, u)], and [empty] if [t] is empty. Note that if [f l > f u], the result of [map] is [empty], by the definition of [create]. If one thinks of an interval as a set of points, rather than a pair of its bounds, then [map] is not the same as the usual mathematical notion of mapping [f] over that set. For example, [~f:(fun x -> x * x)] maps the interval {v [-1,1] v} to {v [1,1] v}, not to {v [0,1] v}. *) val map : 'a t -> f:('a bound -> 'b bound) -> 'b t (** [are_disjoint ts] returns [true] iff the intervals in [ts] are pairwise disjoint. *) val are_disjoint : 'a t list -> bool (** Returns true iff a given set of intervals would be disjoint if considered as open intervals. i.e., (3,4) and (4,5) would count as disjoint. *) val are_disjoint_as_open_intervals : 'a t list -> bool (** Assuming that [ilist1] and [ilist2] are lists of (disjoint) intervals, [list_intersect ilist1 ilist2] returns the list of disjoint intervals that correspond to the intersection of [ilist1] with [ilist2]. *) val list_intersect : 'a t list -> 'a t list -> 'a t list (* Returns true if the intervals, when considered as half-open-intervals, nestle up cleanly one to the next. i.e., if you sort the intervals by the lower bound, then the upper bound of the nth interval is equal to the lower bound of the n+1th interval. The intervals do not need to partition the entire space, they just need to partition their union. *) val half_open_intervals_are_a_partition : 'a t list -> bool end module type Gen_set = sig type 'a t type 'a bound type 'a interval (* An interval set is a set of nonempty disjoint intervals. *) (* [create] creates an interval set containing values between each pair of values. It is an error if the pairs overlap. *) val create : ('a bound * 'a bound) list -> 'a t (* [create_from_intervals] creates an interval set. Empty intervals are dropped. It is an error if the nonempty intervals are not disjoint. *) val create_from_intervals : 'a interval list -> 'a t val contains : 'a t -> 'a bound -> bool val contains_set : container:('a t) -> contained:('a t) -> bool (* The largest and smallest element of the interval set, respectively. Raises Invalid_argument on empty sets. *) val ubound_exn : 'a t -> 'a bound val lbound_exn : 'a t -> 'a bound val ubound : 'a t -> 'a bound option val lbound : 'a t -> 'a bound option end module type S = sig type t with bin_io, sexp type bound type 'a t_ = t type 'a bound_ = bound include Gen with type 'a t := 'a t_ with type 'a bound := 'a bound_ (* [create] has the same type as in [Gen], but adding it here prevents a type-checker issue with nongeneralizable type variables. *) val create : bound -> bound -> t type 'a poly_t val to_poly : t -> bound poly_t type 'a poly_set module Set : sig type t with bin_io, sexp type 'a t_ = t include Gen_set with type 'a t := 'a t_ with type 'a bound := 'a bound_ val to_poly : t -> bound poly_set end with type 'a interval := 'a t_ end module type S1 = sig type 'a t with bin_io, sexp type 'a bound_ = 'a include Gen with type 'a t := 'a t with type 'a bound := 'a bound_ module Set : sig type 'a t with bin_io, sexp include Gen_set with type 'a t := 'a t end with type 'a bound := 'a bound_ with type 'a interval := 'a t end core-113.00.00/src/invariant.ml000066400000000000000000000000361256461075500160720ustar00rootroot00000000000000include Core_kernel.Invariant core-113.00.00/src/iobuf.h000066400000000000000000000002171256461075500150230ustar00rootroot00000000000000/* WHEN YOU CHANGE THIS, CHANGE T.t IN iobuf.ml AS WELL!!! */ enum iobuf_fields { iobuf_buf, iobuf_lo_min, iobuf_lo, iobuf_hi, iobuf_hi_max }; core-113.00.00/src/iobuf.ml000066400000000000000000001541341256461075500152140ustar00rootroot00000000000000open Core_kernel.Std_kernel INCLUDE "core_config.mlh" module Unix = Core_unix module T = struct type t = (* WHEN YOU CHANGE THIS, CHANGE iobuf_fields IN iobuf.h AS WELL!!! *) { mutable buf : Bigstring.t sexp_opaque; (* The data in [buf] is at indices [lo], [lo+1], ... [hi-1]. *) mutable lo_min : int; mutable lo : int; mutable hi : int; mutable hi_max : int; } with fields, sexp_of end open T type (-'read_write, +'seek) t = T.t with sexp_of type seek = Iobuf_intf. seek with sexp_of type no_seek = Iobuf_intf.no_seek with sexp_of module type Bound = Iobuf_intf.Bound with type ('d, 'w) iobuf := ('d, 'w) t let read_only t = t let no_seek t = t let fail t message a sexp_of_a = (* Immediately convert the iobuf to sexp. Otherwise, the iobuf could be modified before conversion and printing. Since we plan to use iobufs for pooled network buffers in practice, this could be very confusing when debugging production systems. *) failwiths message (a, <:sexp_of< (_, _) t >> t) (Tuple.T2.sexp_of_t sexp_of_a ident) module Lo_bound = struct let stale t iobuf = fail iobuf "Iobuf.Lo_bound.restore got stale snapshot" t <:sexp_of< int >> type t = int with sexp_of (* lo *) let window t = t.lo let restore t iobuf = if t < iobuf.lo_min || t > iobuf.hi then stale t iobuf; iobuf.lo <- t; ;; let limit t = t.lo_min end module Hi_bound = struct let stale t iobuf = fail iobuf "Iobuf.Hi_bound.restore got stale snapshot" t <:sexp_of< int >> type t = int with sexp_of (* hi *) let window t = t.hi let restore t iobuf = if t > iobuf.hi_max || t < iobuf.lo then stale t iobuf; iobuf.hi <- t; ;; let limit t = t.hi_max end let length t = t.hi - t.lo let is_empty t = length t = 0 let rewind t = t.lo <- t.lo_min let reset t = t.lo <- t.lo_min; t.hi <- t.hi_max ;; let flip_lo t = t.hi <- t.lo; t.lo <- t.lo_min; ;; let bounded_flip_lo_stale t lo_min = fail t "Iobuf.bounded_flip_lo got stale snapshot" lo_min <:sexp_of< Lo_bound.t >> ;; let bounded_flip_lo t lo_min = if lo_min < t.lo_min || lo_min > t.lo then bounded_flip_lo_stale t lo_min else (t.hi <- t.lo; t.lo <- lo_min) ;; let flip_hi t = t.lo <- t.hi; t.hi <- t.hi_max; ;; let bounded_flip_hi_stale t hi_max = fail t "Iobuf.bounded_flip_hi got stale snapshot" hi_max <:sexp_of< Hi_bound.t >> ;; let bounded_flip_hi t hi_max = if hi_max > t.hi_max || hi_max < t.hi then bounded_flip_hi_stale t hi_max else (t.lo <- t.hi; t.hi <- hi_max) ;; let capacity t = t.hi_max - t.lo_min let invariant _ _ t = try Fields.Direct.iter t ~buf:(fun _ _ _ -> ()) ~lo_min:(fun _ _ lo_min -> assert (lo_min >= 0); assert (lo_min = t.hi_max - capacity t)) ~hi_max:(fun _ _ hi_max -> assert (hi_max >= t.lo); assert (hi_max = t.lo_min + capacity t)) ~lo:(fun _ _ lo -> assert (lo >= t.lo_min); assert (lo <= t.hi)) ~hi:(fun _ _ hi -> assert (hi >= t.lo); assert (hi <= t.hi_max)) with e -> fail t "Iobuf.invariant failed" e <:sexp_of< exn >> ;; (* We want [check_range] inlined, so we don't want a string constant in there. *) let bad_range ~pos ~len t = fail t "Iobuf got invalid range" (`pos pos, `len len) <:sexp_of< [ `pos of int ] * [ `len of int ] >>; ;; let check_range t ~pos ~len = if pos < 0 || len < 0 || len > length t - pos then bad_range ~pos ~len t; ;; let of_bigstring ?pos ?len buf = let str_len = Bigstring.length buf in let pos = match pos with | None -> 0 | Some pos -> if pos < 0 || pos > str_len then failwiths "Iobuf.of_bigstring got invalid pos" (pos, `str_len str_len) (<:sexp_of< int * [ `str_len of int ]>>); pos in let len = match len with | None -> str_len - pos | Some len -> let max_len = str_len - pos in if len < 0 || len > max_len then failwiths "Iobuf.of_bigstring got invalid len" (len, `max_len max_len) (<:sexp_of< int * [ `max_len of int ] >>); len in let lo = pos in let hi = pos + len in { buf; lo_min = lo; lo; hi; hi_max = hi } ;; let sub_shared ?(pos = 0) ?len t = let len = match len with | None -> length t - pos | Some len -> len in check_range t ~pos ~len; let lo = t.lo + pos in let hi = lo + len in { buf = t.buf; lo_min = lo; lo; hi; hi_max = hi; } ;; let set_bounds_and_buffer_sub ?(pos = 0) ?len ~src ~dst () = let len = match len with | None -> length src - pos | Some len -> len in check_range src ~pos ~len; let lo = src.lo + pos in let hi = lo + len in dst.lo_min <- lo; dst.lo <- lo; dst.hi <- hi; dst.hi_max <- hi; dst.buf <- src.buf ;; let set_bounds_and_buffer ~src ~dst = dst.lo_min <- src.lo_min; dst.lo <- src.lo; dst.hi <- src.hi; dst.hi_max <- src.hi_max; dst.buf <- src.buf ;; let narrow_lo t = t.lo_min <- t.lo let narrow_hi t = t.hi_max <- t.hi let narrow t = narrow_lo t; narrow_hi t let unsafe_resize t ~len = t.hi <- t.lo + len let resize t ~len = if len < 0 then bad_range t ~len ~pos:0; let hi = t.lo + len in if hi > t.hi_max then bad_range t ~len ~pos:0; t.hi <- hi; ;; let protect_window_and_bounds t ~f = let lo = t.lo in let hi = t.hi in let lo_min = t.lo_min in let hi_max = t.hi_max in try t.lo_min <- lo; t.hi_max <- hi; let result = f t in t.lo <- lo; t.hi <- hi; t.lo_min <- lo_min; t.hi_max <- hi_max; result with | exn -> begin t.lo <- lo; t.hi <- hi; t.lo_min <- lo_min; t.hi_max <- hi_max; raise exn end let create ~len = if len < 0 then failwiths "Iobuf.create got negative len" len <:sexp_of< int >>; of_bigstring (Bigstring.create len); ;; let to_string ?len t = let len = match len with | Some len -> check_range t ~pos:0 ~len; len | None -> length t in Bigstring.to_string t.buf ~pos:t.lo ~len let of_string s = of_bigstring (Bigstring.of_string s) module Hexdump = struct let half_line_length = 8 let full_line_length = half_line_length * 2 let get_char_within t ~lo ~hi ~pos = if pos < 0 || pos >= (hi-lo) then None else Some (Bigstring.get t.buf (pos+lo)) let half_line t ~lo ~hi ~pos ~sep ~f = let strs = ref [] in for i = pos + half_line_length - 1 downto pos do strs := f (get_char_within t ~lo ~hi ~pos:i) :: !strs done; String.concat ~sep (!strs) let hex_char = function | Some c -> sprintf "%02x" (Char.to_int c) | None -> " " let ascii_char = function | Some c -> if Char.is_print c then String.of_char c else "." | None -> " " let hex_half_line t ~lo ~hi ~pos = half_line t ~lo ~hi ~pos ~sep:" " ~f:hex_char let ascii_half_line t ~lo ~hi ~pos = half_line t ~lo ~hi ~pos ~sep:"" ~f:ascii_char let line_index ~lo ~hi ~pos = let len = hi-lo in if len <= (1 lsl 8) then sprintf "0x%02x" pos else if len <= (1 lsl 16) then sprintf "0x%04x" pos else if len <= (1 lsl 24) then sprintf "0x%06x" pos else if len <= (1 lsl 32) then sprintf "0x%08x" pos else if len <= (1 lsl 40) then sprintf "0x%010x" pos else if len <= (1 lsl 48) then sprintf "0x%012x" pos else if len <= (1 lsl 56) then sprintf "0x%014x" pos else sprintf "0x%016x" pos let to_string_line t ~lo ~hi ~pos = let pos1 = pos in let pos2 = pos + half_line_length in sprintf "%s: %s %s %s %s" (line_index ~lo ~hi ~pos) (hex_half_line t ~lo ~hi ~pos:pos1) (ascii_half_line t ~lo ~hi ~pos:pos1) (ascii_half_line t ~lo ~hi ~pos:pos2) (hex_half_line t ~lo ~hi ~pos:pos2) let to_string_contents t ~lo ~hi = if lo >= hi then "" else let rec loop ~pos ~rev_lines = if pos >= hi-lo then String.concat ~sep:"\n" (List.rev rev_lines) else loop ~pos:(pos + full_line_length) ~rev_lines:(to_string_line t ~lo ~hi ~pos :: rev_lines) in loop ~pos:0 ~rev_lines:[] let to_string_header t ~desc = sprintf "Iobuf: bigstring length %d; limits [%d,%d]; window [%d,%d]; %s:\n" (Bigstring.length t.buf) t.lo_min t.hi_max t.lo t.hi desc let to_string_within t ~lo ~hi ~desc = to_string_header t ~desc ^ to_string_contents t ~lo ~hi let to_string_whole t = to_string_within t ~lo:0 ~hi:(Bigstring.length t.buf) ~desc:"contents" let to_string_limits t = to_string_within t ~lo:t.lo_min ~hi:t.hi_max ~desc:"contents within limits" let to_string_window t = to_string_within t ~lo:t.lo ~hi:t.hi ~desc:"contents within window" let to_string ?(bounds=`Limits) t = match bounds with | `Whole -> to_string_whole t | `Limits -> to_string_limits t | `Window -> to_string_window t end let to_string_hum = Hexdump.to_string (* We used to do it like {v let unsafe_with_range t ~pos f = f t.buf ~pos:(t.lo + pos); ;; let with_range t ~pos ~len f = check_range t ~pos ~len; unsafe_with_range t ~pos f; ;; let inc_lo t amount = t.lo <- t.lo + amount (** [unsafe_with_advance] and [unsafe_with_range] forego range checks for code that does macro range checks, like we want to do in [Parachute_fix.Std.Protocol]. Esp. [Consume.Unsafe.int32_le] for unrolled character scanning. *) let unsafe_with_advance t ~len f = let result = unsafe_with_range t ~pos:0 f in inc_lo t len; result; ;; let with_advance t ~len f = check_range t ~pos:0 ~len; unsafe_with_advance t ~len f; ;; (* pulled out and type-constrained for inlining *) let ignore_range (_ : Bigstring.t) ~pos:(_ : int) = () let advance t len = with_advance t ~len ignore_range v} but higher order functions don't get inlined, even in simple uses like advance. Therefor, we stick to first order. *) let unsafe_buf_pos t ~pos = t.lo + pos let buf_pos_exn t ~pos ~len = check_range t ~pos ~len; unsafe_buf_pos t ~pos let unsafe_advance t n = t.lo <- t.lo + n let advance t len = check_range t ~len ~pos:0; unsafe_advance t len (* Unsafe, inline-able version of Bigstring.get. *) external bigstring_unsafe_get : Bigstring.t -> pos:int -> char = "%caml_ba_unsafe_ref_1" external bigstring_unsafe_set : Bigstring.t -> pos:int -> char -> unit = "%caml_ba_unsafe_set_1" (* Note that we can get buf.{pos} inlined by ensuring that it's monomorphically typed, but we can't always get the containing function inlined. *) (* Similarly, we need the following intermediate functions for the primitives to be inlined into. (Not intuitive, but apparently necessary.) *) let bigstring_unsafe_get b ~pos = bigstring_unsafe_get b ~pos let bigstring_unsafe_set b ~pos c = bigstring_unsafe_set b ~pos c module Char_elt = struct include Char let of_bool = function true -> '0' | false -> '1' end module T_src = struct type t = T.t with sexp_of let create = create let length = length let get t pos = bigstring_unsafe_get t.buf ~pos:(buf_pos_exn t ~len:1 ~pos) let set t pos c = bigstring_unsafe_set t.buf ~pos:(buf_pos_exn t ~len:1 ~pos) c end module String_dst = struct include String let unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len = Bigstring.To_string.unsafe_blit ~src:src.buf ~src_pos:(unsafe_buf_pos src ~pos:src_pos) ~dst ~dst_pos ~len let create ~len = create len end module Bigstring_dst = struct include Bigstring let unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len = Bigstring.unsafe_blit ~src:src.buf ~src_pos:(unsafe_buf_pos src ~pos:src_pos) ~dst ~dst_pos ~len let create ~len = create len end let compact t = let len = t.hi - t.lo in Bigstring.blit ~src:t.buf ~src_pos:t.lo ~len ~dst:t.buf ~dst_pos:t.lo_min; t.lo <- t.lo_min + len; t.hi <- t.hi_max; ;; let bounded_compact_stale t lo_min hi_max = fail t "Iobuf.bounded_compact got stale snapshot" (lo_min, hi_max) <:sexp_of< Lo_bound.t * Hi_bound.t >> ;; let bounded_compact t lo_min hi_max = let len = t.hi - t.lo in if hi_max > t.hi_max || hi_max < lo_min + len || lo_min < t.lo_min then bounded_compact_stale t lo_min hi_max else (Bigstring.blit ~src:t.buf ~src_pos:t.lo ~len ~dst:t.buf ~dst_pos:lo_min; t.lo <- lo_min + len; t.hi <- hi_max) (* Sys.word_size is determined only at runtime, but we need it to be a compile-time constant to generate good code for Consume.int8, etc. *) let word_size = 64 TEST = Sys.word_size = word_size let read_bin_prot reader t ~pos = let buf_pos = unsafe_buf_pos t ~pos in let pos_ref = ref buf_pos in let a = reader.Bin_prot.Type_class.read t.buf ~pos_ref in let len = !pos_ref - buf_pos in check_range t ~pos ~len; (a, len) module Consume = struct type src = (read, seek) t module To (Dst : sig type t with sexp_of val create : len:int -> t val length : t -> int val get : t -> int -> char val set : t -> int -> char -> unit val unsafe_blit : (T.t, t) Blit.blit end) = struct include Blit.Make_distinct (Char_elt) (T_src) (Dst) let blit ~src ~dst ~dst_pos ~len = blit ~src ~src_pos:0 ~dst ~dst_pos ~len; unsafe_advance src len let blito ~src ?(src_len = length src) ~dst ?dst_pos () = blito ~src ~src_pos:0 ~src_len ~dst ?dst_pos (); unsafe_advance src src_len let unsafe_blit ~src ~dst ~dst_pos ~len = unsafe_blit ~src ~src_pos:0 ~dst ~dst_pos ~len; unsafe_advance src len let sub src ~len = let dst = sub src ~pos:0 ~len in unsafe_advance src len; dst let subo ?len src = let len = match len with None -> length src | Some len -> len in let dst = subo ~pos:0 ~len src in unsafe_advance src len; dst end module To_string = To (String_dst) module To_bigstring = To (Bigstring_dst) type nonrec ('a, 'd, 'w) t = ('d, seek) t -> 'a constraint 'd = [> read ] let uadv t n x = unsafe_advance t n; x let pos t len = buf_pos_exn t ~pos:0 ~len let tail_padded_fixed_string ~padding ~len t = uadv t len (Bigstring.get_tail_padded_fixed_string t.buf ~pos:(pos t len) ~padding ~len ()) ;; let string ?(str_pos = 0) ?len t = let len = match len with None -> length t | Some l -> l in let dst = String.create (len + str_pos) in To_string.blit ~src:t ~dst ~len ~dst_pos:str_pos; dst ;; let bigstring ?(str_pos = 0) ?len t = let len = match len with None -> length t | Some l -> l in let dst = Bigstring.create (len + str_pos) in To_bigstring.blit ~src:t ~dst ~len ~dst_pos:str_pos; dst ;; let bin_prot reader t = let (a, len) = read_bin_prot reader t ~pos:0 in uadv t len a ;; TEST_UNIT "bin_prot char" = let t = of_string "abc" in let a = bin_prot Char.bin_reader_t t in let b = bin_prot Char.bin_reader_t t in <:test_eq< char >> a 'a'; <:test_eq< char >> b 'b'; <:test_eq< string >> (to_string t) "c"; ;; TEST_UNIT "bin_prot int" = let ints = [ 0; 1; -1; 12345; -67890; Int.min_value; Int.max_value; 666 ] in let buf = Bigstring.create 1000 in let _end_pos = List.fold ints ~init:0 ~f:(fun pos i -> Int.bin_write_t buf ~pos i) in let t = of_bigstring buf in List.iter ints ~f:(fun i -> <:test_eq< int >> i (bin_prot Int.bin_reader_t t)); ;; open Bigstring let len = 1 let char t = uadv t len (bigstring_unsafe_get t.buf ~pos:(pos t len)) let uint8 t = Char.to_int (char t) let int8 t = (uint8 t lsl (word_size - 9)) asr (word_size - 9) let len = 2 let int16_be t = uadv t len (unsafe_get_int16_be t.buf ~pos:(pos t len)) let int16_le t = uadv t len (unsafe_get_int16_le t.buf ~pos:(pos t len)) let uint16_be t = uadv t len (unsafe_get_uint16_be t.buf ~pos:(pos t len)) let uint16_le t = uadv t len (unsafe_get_uint16_le t.buf ~pos:(pos t len)) let len = 4 let int32_be t = uadv t len (unsafe_get_int32_be t.buf ~pos:(pos t len)) let int32_le t = uadv t len (unsafe_get_int32_le t.buf ~pos:(pos t len)) let uint32_be t = uadv t len (unsafe_get_uint32_be t.buf ~pos:(pos t len)) let uint32_le t = uadv t len (unsafe_get_uint32_le t.buf ~pos:(pos t len)) let len = 8 let int64_be t = uadv t len (unsafe_get_int64_be_exn t.buf ~pos:(pos t len)) let int64_le t = uadv t len (unsafe_get_int64_le_exn t.buf ~pos:(pos t len)) let int64_t_be t = uadv t len (unsafe_get_int64_t_be t.buf ~pos:(pos t len)) let int64_t_le t = uadv t len (unsafe_get_int64_t_le t.buf ~pos:(pos t len)) let int64_be_trunc t = uadv t len (unsafe_get_int64_be_trunc t.buf ~pos:(pos t len)) let int64_le_trunc t = uadv t len (unsafe_get_int64_le_trunc t.buf ~pos:(pos t len)) end let write_bin_prot writer t ~pos a = let len = writer.Bin_prot.Type_class.size a in let buf_pos = buf_pos_exn t ~pos ~len in let stop_pos = writer.Bin_prot.Type_class.write t.buf ~pos:buf_pos a in if stop_pos - buf_pos = len then len else fail t "Iobuf.write_bin_prot got unexpected number of bytes written \ (Bin_prot bug: Type_class.write disagrees with .size)" (`size_len len, `buf_pos buf_pos, `write_stop_pos stop_pos) <:sexp_of< [ `size_len of int ] * [ `buf_pos of int ] * [ `write_stop_pos of int ] >> (* [Itoa] provides a range of functions for integer to ASCII conversion, used by [Poke], [Fill] and their [Unsafe] versions. The implementation here is done in terms of negative decimals due to the properties of [Int.min_value]. Since the result of [Int.(abs min_value)] is [Int.min_value], an attempt to utilize a positive decimal loop by writing the sign and calling [Int.abs x] fails. The converse, with [- Int.max_value] works for both cases. *) module Itoa = struct (* [num_digits x] returns the number of digits in [x] for non-positive integers ([num_digits 0] is defined as 1). The below tends to perform better than a binary search or [/= 10 while <> 0], likely due to decimal values for our applications skewing towards smaller numbers. *) let _10e9 = 1_000_000_000 let num_digits x = if x > -10 then 1 else if x > -100 then 2 else if x > -1000 then 3 else if x > -10000 then 4 else if x > -100000 then 5 else if x > -1000000 then 6 else if x > -10000000 then 7 else if x > -100000000 then 8 else if x > -1000000000 then 9 else IFDEF ARCH_SIXTYFOUR THEN if x > _10e9 * -10 then 10 else if x > _10e9 * -100 then 11 else if x > _10e9 * -1000 then 12 else if x > _10e9 * -10000 then 13 else if x > _10e9 * -100000 then 14 else if x > _10e9 * -1000000 then 15 else if x > _10e9 * -10000000 then 16 else if x > _10e9 * -100000000 then 17 else if x > _10e9 * -1000000000 then 18 else 19 ELSE 10 ENDIF TEST = String.length (Int.to_string Int.min_value) <= 19 + 1 (* Despite the div/mod by a constant optimizations, it's a slight savings to avoid a second div/mod. Note also that passing in an [int ref], rather than creating the ref locally here, results in allocation on the benchmarks. *) let unsafe_poke_negative_decimal_without_sign t ~pos ~len int = let int = ref int in for pos = pos + len - 1 downto pos do let x = !int in int := !int / 10; bigstring_unsafe_set t.buf ~pos (Char.unsafe_of_int (48 + ((- x) + !int * 10))); done let unsafe_poke_negative_decimal t ~pos ~len int = bigstring_unsafe_set t.buf ~pos '-'; (* +1 and -1 to account for '-' *) unsafe_poke_negative_decimal_without_sign t ~pos:(pos + 1) ~len:(len - 1) int let poke_decimal t ~pos int = if int < 0 then ( let len = 1 + num_digits int in unsafe_poke_negative_decimal t ~pos:(buf_pos_exn t ~pos ~len) ~len int; len) else ( let len = num_digits (- int) in unsafe_poke_negative_decimal_without_sign t ~pos:(buf_pos_exn t ~pos ~len) ~len (- int); len) let unsafe_poke_decimal t ~pos int = if int < 0 then ( let len = 1 + num_digits int in unsafe_poke_negative_decimal t ~pos:(unsafe_buf_pos t ~pos) ~len int; len) else ( let len = num_digits (- int) in unsafe_poke_negative_decimal_without_sign t ~pos:(unsafe_buf_pos t ~pos) ~len (- int); len) end module Fill = struct type nonrec ('a, 'd, 'w) t = (read_write, seek) t -> 'a -> unit constraint 'd = [> read ] let pos t len = buf_pos_exn t ~pos:0 ~len let uadv = unsafe_advance let tail_padded_fixed_string ~padding ~len t src = Bigstring.set_tail_padded_fixed_string ~padding ~len t.buf ~pos:(pos t len) src; uadv t len ;; let string ?str_pos:(src_pos = 0) ?len t src = let len = match len with Some l -> l | None -> String.length src - src_pos in Bigstring.From_string.blit ~src ~src_pos ~len ~dst:t.buf ~dst_pos:(pos t len); uadv t len ;; let bigstring ?str_pos:(src_pos = 0) ?len t src = let len = match len with Some l -> l | None -> Bigstring.length src - src_pos in Bigstring.blit ~src ~src_pos ~len ~dst:t.buf ~dst_pos:(pos t len); uadv t len ;; let bin_prot writer t a = write_bin_prot writer t ~pos:0 a |> uadv t open Bigstring let len = 1 let char t c = bigstring_unsafe_set t.buf c ~pos:(pos t len); uadv t len let uint8 t i = char t (Char.unsafe_of_int i) let int8 t i = char t (Char.unsafe_of_int i) let len = 2 let int16_be t i = unsafe_set_int16_be t.buf i ~pos:(pos t len); uadv t len let int16_le t i = unsafe_set_int16_le t.buf i ~pos:(pos t len); uadv t len let uint16_be t i = unsafe_set_uint16_be t.buf i ~pos:(pos t len); uadv t len let uint16_le t i = unsafe_set_uint16_le t.buf i ~pos:(pos t len); uadv t len let len = 4 let int32_be t i = unsafe_set_int32_be t.buf i ~pos:(pos t len); uadv t len let int32_le t i = unsafe_set_int32_le t.buf i ~pos:(pos t len); uadv t len let uint32_be t i = unsafe_set_uint32_be t.buf i ~pos:(pos t len); uadv t len let uint32_le t i = unsafe_set_uint32_le t.buf i ~pos:(pos t len); uadv t len let len = 8 let int64_be t i = unsafe_set_int64_be t.buf i ~pos:(pos t len); uadv t len let int64_le t i = unsafe_set_int64_le t.buf i ~pos:(pos t len); uadv t len let int64_t_be t i = unsafe_set_int64_t_be t.buf i ~pos:(pos t len); uadv t len let int64_t_le t i = unsafe_set_int64_t_le t.buf i ~pos:(pos t len); uadv t len let int64_be_trunc t i = unsafe_set_int64_be t.buf i ~pos:(pos t len); uadv t len let int64_le_trunc t i = unsafe_set_int64_le t.buf i ~pos:(pos t len); uadv t len let decimal t i = uadv t (Itoa.poke_decimal t ~pos:0 i) end module Peek = struct type src = (read, no_seek) t module To_string = Blit.Make_distinct (Char_elt) (T_src) (String_dst) module To_bigstring = Blit.Make_distinct (Char_elt) (T_src) (Bigstring_dst) type nonrec ('a, 'd, 'w) t = ('d, 'w) t -> pos:int -> 'a constraint 'd = [> read ] let spos = buf_pos_exn (* "safe position" *) let tail_padded_fixed_string ~padding ~len t ~pos = Bigstring.get_tail_padded_fixed_string t.buf ~padding ~len ~pos:(spos t ~len ~pos) () ;; let string ?str_pos:(dst_pos = 0) ?len t ~pos = let len = match len with None -> length t - pos | Some l -> l in let dst = String.create (len + dst_pos) in Bigstring.To_string.blit ~src:t.buf ~src_pos:(spos t ~len ~pos) ~len ~dst ~dst_pos; dst ;; let bigstring ?str_pos:(dst_pos = 0) ?len t ~pos = let len = match len with None -> length t - pos | Some l -> l in let dst = Bigstring.create (len + dst_pos) in Bigstring.blit ~src:t.buf ~src_pos:(spos t ~len ~pos) ~len ~dst ~dst_pos; dst ;; let bin_prot reader t ~pos = read_bin_prot reader t ~pos |> fst TEST_UNIT "bin_prot char" = let t = of_string "abc" in let a = bin_prot Char.bin_reader_t t ~pos:0 in let b = bin_prot Char.bin_reader_t t ~pos:1 in <:test_eq< char >> a 'a'; <:test_eq< char >> b 'b'; <:test_eq< string >> (to_string t) "abc"; ;; TEST_UNIT "bin_prot int" = let ints = [ 0; 1; -1; 12345; -67890; Int.min_value; Int.max_value; 666 ] in let buf = Bigstring.create 1000 in let end_pos = List.fold ints ~init:0 ~f:(fun pos i -> Int.bin_write_t buf ~pos i) in let t = of_bigstring buf in List.fold ints ~init:0 ~f:(fun pos i -> <:test_eq< int >> i (bin_prot Int.bin_reader_t t ~pos); pos + Int.bin_size_t i) |> (fun end_pos' -> <:test_eq< int >> end_pos end_pos'); ;; open Bigstring let char t ~pos = T_src.get t pos (* int8 accessors are slow C calls. Use the fast char primitive. *) let uint8 t ~pos = Char.to_int (char t ~pos) let int8 t ~pos = (uint8 t ~pos lsl (word_size - 9)) asr (word_size - 9) let len = 2 let int16_be t ~pos = unsafe_get_int16_be t.buf ~pos:(spos t ~len ~pos) let int16_le t ~pos = unsafe_get_int16_le t.buf ~pos:(spos t ~len ~pos) let uint16_be t ~pos = unsafe_get_uint16_be t.buf ~pos:(spos t ~len ~pos) let uint16_le t ~pos = unsafe_get_uint16_le t.buf ~pos:(spos t ~len ~pos) let len = 4 let int32_be t ~pos = unsafe_get_int32_be t.buf ~pos:(spos t ~len ~pos) let int32_le t ~pos = unsafe_get_int32_le t.buf ~pos:(spos t ~len ~pos) let uint32_be t ~pos = unsafe_get_uint32_be t.buf ~pos:(spos t ~len ~pos) let uint32_le t ~pos = unsafe_get_uint32_le t.buf ~pos:(spos t ~len ~pos) let len = 8 let int64_be t ~pos = unsafe_get_int64_be_exn t.buf ~pos:(spos t ~len ~pos) let int64_le t ~pos = unsafe_get_int64_le_exn t.buf ~pos:(spos t ~len ~pos) let int64_t_be t ~pos = unsafe_get_int64_t_be t.buf ~pos:(spos t ~len ~pos) let int64_t_le t ~pos = unsafe_get_int64_t_le t.buf ~pos:(spos t ~len ~pos) let int64_be_trunc t ~pos = unsafe_get_int64_be_trunc t.buf ~pos:(spos t ~len ~pos) let int64_le_trunc t ~pos = unsafe_get_int64_le_trunc t.buf ~pos:(spos t ~len ~pos) end module Poke = struct type nonrec ('a, 'd, 'w) t = (read_write, 'w) t -> pos:int -> 'a -> unit constraint 'd = [> read ] let spos = buf_pos_exn (* "safe position" *) let tail_padded_fixed_string ~padding ~len t ~pos src = Bigstring.set_tail_padded_fixed_string ~padding ~len t.buf ~pos:(spos t ~len ~pos) src ;; let string ?str_pos:(src_pos = 0) ?len t ~pos src = let len = match len with None -> String.length src - src_pos | Some l -> l in Bigstring.From_string.blit ~src ~src_pos ~len ~dst:t.buf ~dst_pos:(spos t ~len ~pos) ;; let bigstring ?str_pos:(src_pos = 0) ?len t ~pos src = let len = match len with None -> Bigstring.length src - src_pos | Some l -> l in Bigstring.blit ~src ~src_pos ~len ~dst:t.buf ~dst_pos:(spos t ~len ~pos) ;; let bin_prot writer t ~pos a = write_bin_prot writer t ~pos a |> (ignore : int -> unit) TEST_UNIT = let t = of_string "abc" in bin_prot Char.bin_writer_t t 'd' ~pos:0; bin_prot Char.bin_writer_t t 'e' ~pos:1; <:test_eq< string >> "dec" (to_string t); flip_lo t; assert (try bin_prot String.bin_writer_t t "fgh" ~pos:0; false with _ -> true); assert (is_empty t); reset t; <:test_eq< string >> "dec" (to_string t); bin_prot Char.bin_writer_t t 'i' ~pos:0; <:test_eq< string >> "iec" (to_string t); ;; open Bigstring let char t ~pos c = T_src.set t pos c let uint8 t ~pos i = char t ~pos (Char.unsafe_of_int i) let int8 t ~pos i = char t ~pos (Char.unsafe_of_int i) let len = 2 let int16_be t ~pos i = unsafe_set_int16_be t.buf ~pos:(spos t ~len ~pos) i let int16_le t ~pos i = unsafe_set_int16_le t.buf ~pos:(spos t ~len ~pos) i let uint16_be t ~pos i = unsafe_set_uint16_be t.buf ~pos:(spos t ~len ~pos) i let uint16_le t ~pos i = unsafe_set_uint16_le t.buf ~pos:(spos t ~len ~pos) i let len = 4 let int32_be t ~pos i = unsafe_set_int32_be t.buf ~pos:(spos t ~len ~pos) i let int32_le t ~pos i = unsafe_set_int32_le t.buf ~pos:(spos t ~len ~pos) i let uint32_be t ~pos i = unsafe_set_uint32_be t.buf ~pos:(spos t ~len ~pos) i let uint32_le t ~pos i = unsafe_set_uint32_le t.buf ~pos:(spos t ~len ~pos) i let len = 8 let int64_be t ~pos i = unsafe_set_int64_be t.buf ~pos:(spos t ~len ~pos) i let int64_le t ~pos i = unsafe_set_int64_le t.buf ~pos:(spos t ~len ~pos) i let int64_t_be t ~pos i = unsafe_set_int64_t_be t.buf ~pos:(spos t ~len ~pos) i let int64_t_le t ~pos i = unsafe_set_int64_t_le t.buf ~pos:(spos t ~len ~pos) i let int64_be_trunc t ~pos i = unsafe_set_int64_be t.buf ~pos:(spos t ~len ~pos) i let int64_le_trunc t ~pos i = unsafe_set_int64_le t.buf ~pos:(spos t ~len ~pos) i let decimal = Itoa.poke_decimal end let crc32 { buf ; lo ; hi ; _ } = Crc.bigstring_crc32 buf ~pos:lo ~len:(hi - lo) module Blit = struct type 'rw t_no_seek = ('rw, no_seek) t module T_dst = struct include T_src let unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len = Bigstring.unsafe_blit ~len ~src:src.buf ~src_pos:(buf_pos_exn src ~pos:src_pos ~len) ~dst:dst.buf ~dst_pos:(buf_pos_exn dst ~pos:dst_pos ~len) end include Blit.Make (Char_elt) (T_dst) (* Workaround the inability of the compiler to inline in the presence of functors. *) let unsafe_blit = T_dst.unsafe_blit end module Blit_consume = struct let unsafe_blit ~src ~dst ~dst_pos ~len = Blit.unsafe_blit ~src ~src_pos:0 ~dst ~dst_pos ~len; unsafe_advance src len let blit ~src ~dst ~dst_pos ~len = Blit.blit ~src ~src_pos:0 ~dst ~dst_pos ~len; unsafe_advance src len let blito ~src ?(src_len = length src) ~dst ?(dst_pos = 0) () = blit ~src ~dst ~dst_pos ~len:src_len let sub src ~len = let dst = Blit.sub src ~pos:0 ~len in unsafe_advance src len; dst let subo ?len src = let len = match len with None -> length src | Some len -> len in sub src ~len end module Blit_fill = struct let unsafe_blit ~src ~src_pos ~dst ~len = Blit.unsafe_blit ~src ~src_pos ~dst ~dst_pos:0 ~len; unsafe_advance dst len let blit ~src ~src_pos ~dst ~len = Blit.blit ~src ~src_pos ~dst ~dst_pos:0 ~len; unsafe_advance dst len let blito ~src ?(src_pos = 0) ?(src_len = length src - src_pos) ~dst () = blit ~src ~src_pos ~dst ~len:src_len end module Blit_consume_and_fill = struct let unsafe_blit ~src ~dst ~len = if phys_equal src dst then advance src len else begin Blit.unsafe_blit ~src ~src_pos:0 ~dst ~dst_pos:0 ~len; unsafe_advance src len; unsafe_advance dst len end let blit ~src ~dst ~len = if phys_equal src dst then advance src len else begin Blit.blit ~src ~src_pos:0 ~dst ~dst_pos:0 ~len; unsafe_advance src len; unsafe_advance dst len end let blito ~src ?(src_len = length src) ~dst () = blit ~src ~dst ~len:src_len end let bin_prot_length_prefix_bytes = 4 let consume_bin_prot t bin_prot_reader = let result = if length t < bin_prot_length_prefix_bytes then error "Iobuf.consume_bin_prot not enough data to read length" t (<:sexp_of< (_, _) t >>) else begin let mark = t.lo in let v_len = Consume.int32_be t in if v_len > length t then begin t.lo <- mark; error "Iobuf.consume_bin_prot not enough data to read value" (v_len, t) (<:sexp_of< int * (_, _) t >>); end else Ok (Consume.bin_prot bin_prot_reader t) end in result; ;; let fill_bin_prot t writer v = let v_len = writer.Bin_prot.Type_class.size v in let need = v_len + bin_prot_length_prefix_bytes in let result = if need > length t then error "Iobuf.fill_bin_prot not enough space" (need, t) (<:sexp_of< int * (_, _) t >>) else begin Fill.int32_be t v_len; Fill.bin_prot writer t v; Ok (); end in result; ;; module Expert = struct let buf t = t.buf let hi_max t = t.hi_max let hi t = t.hi let lo t = t.lo let lo_min t = t.lo_min end module File_descr = Iobuf_intf.Unix.File_descr let read_assume_fd_is_nonblocking t fd = let nread = Bigstring.read_assume_fd_is_nonblocking fd t.buf ~pos:t.lo ~len:(length t) in if Syscall_result.Int.is_ok nread then unsafe_advance t (Syscall_result.Int.ok_exn nread); Syscall_result.ignore_ok_value nread ;; let pread_assume_fd_is_nonblocking t fd ~offset = let nread = Bigstring.pread_assume_fd_is_nonblocking fd ~offset t.buf ~pos:t.lo ~len:(length t) in unsafe_advance t nread ;; let recvfrom_assume_fd_is_nonblocking t fd = let nread, sockaddr = Bigstring.recvfrom_assume_fd_is_nonblocking fd t.buf ~pos:t.lo ~len:(length t) in unsafe_advance t nread; sockaddr ;; (* recvmmsg based on bigstring.ml *) IFDEF RECVMMSG THEN external unsafe_recvmmsg_assume_fd_is_nonblocking : (File_descr.t -> (read_write, seek) t array -> int -> Unix.sockaddr array option -> Unix.Syscall_result.Int.t) = "iobuf_recvmmsg_assume_fd_is_nonblocking_stub" TEST_MODULE = struct let expect_invalid_argument ?msg f = try ignore (f () : Unix.Syscall_result.Int.t); assert false with Invalid_argument s -> match msg with | None -> () | Some x -> <:test_result< string >> s ~expect:x ;; let check_invalid ?msg count = let fd = Unix.socket ~domain:PF_INET ~kind:SOCK_DGRAM ~protocol:0 in expect_invalid_argument ?msg (fun () -> unsafe_recvmmsg_assume_fd_is_nonblocking fd [||] count None) TEST_UNIT "unsafe_recvmmsg_assume_fd_is_nonblocking: check count bounds" = check_invalid (-1); check_invalid Int.min_value; check_invalid 65; (* RECVMMSG_MAX_COUNT = 64 *) ( IFDEF ARCH_SIXTYFOUR THEN (* We are assuming that [unsigned int] is 32 bits wide. *) check_invalid (Int64.to_int_exn 0xFFFF_FFFFL); (* exceeds RECVMMSG_MAX_COUNT *) check_invalid (Int64.to_int_exn 0x1FFFF_FFFFL); (* exceeds unsigned int *) ENDIF ) ;; end let recvmmsg_assume_fd_is_nonblocking fd ?count ?srcs ts = let loc = "Iobuf.recvmmsg_assume_fd_is_nonblocking" in let count = Option.value count ~default:(Array.length ts) in if count < 0 then invalid_arg (loc ^ ": count < 0"); if count > Array.length ts then invalid_arg (loc ^ ": count > n_iobufs"); begin match srcs with | None -> () | Some a -> if count > Array.length a then invalid_arg (loc ^ ": count > n_srcs") end; unsafe_recvmmsg_assume_fd_is_nonblocking fd ts count srcs ;; let recvmmsg_assume_fd_is_nonblocking = (* At Jane Street, we link with [--wrap recvmmsg] so that we can use our own wrapper around [recvmmsg]. This allows us to compile an executable on a machine that has recvmmsg (e.g., CentOS 6) but then run the executable on a machine that does not (e.g., CentOS 5), but that has our wrapper library. We set up our wrapper so that when running on a machine that doesn't have it, [recvmmsg] always returns -1 and sets errno to ENOSYS. *) match Unix.Syscall_result.Int.to_result (recvmmsg_assume_fd_is_nonblocking (File_descr.of_int (-1)) [||]) with | Error ENOSYS -> Or_error.unimplemented "Iobuf.recvmmsg_assume_fd_is_nonblocking" | _ -> Ok recvmmsg_assume_fd_is_nonblocking ;; let recvmmsg_assume_fd_is_nonblocking_no_options fd ~count ts = let loc = "Iobuf.recvmmsg_assume_fd_is_nonblocking_no_options" in if count < 0 then invalid_arg (loc ^ ": count < 0"); if count > Array.length ts then invalid_arg (loc ^ ": count > n_iobufs"); unsafe_recvmmsg_assume_fd_is_nonblocking fd ts count None ;; let recvmmsg_assume_fd_is_nonblocking_no_options = match Unix.Syscall_result.Int.to_result (recvmmsg_assume_fd_is_nonblocking_no_options (File_descr.of_int (-1)) ~count:0 [||]) with | Error ENOSYS -> Or_error.unimplemented "Iobuf.recvmmsg_assume_fd_is_nonblocking_no_options" | _ -> Ok recvmmsg_assume_fd_is_nonblocking_no_options ;; ELSE (* NDEF RECVMMSG *) let recvmmsg_assume_fd_is_nonblocking = Or_error.unimplemented "Iobuf.recvmmsg_assume_fd_is_nonblocking" ;; let recvmmsg_assume_fd_is_nonblocking_no_options = Or_error.unimplemented "Iobuf.recvmmsg_assume_fd_is_nonblocking_no_options" ;; ENDIF (* RECVMMSG *) let unsafe_sent t result = if Syscall_result.Int.is_ok result then (unsafe_advance t (Syscall_result.Int.ok_exn result); Syscall_result.unit) else Syscall_result.Int.reinterpret_error_exn result (* This function and the one below have a 'fun () ->' in front of them because the value restriction that comes from applying Or_error.map prevents the generalization of the phantom types variables in the iobuf types. Or_error.map could be inlined though. *) let send_nonblocking_no_sigpipe () = Or_error.map Bigstring.send_nonblocking_no_sigpipe ~f:(fun send -> fun t fd -> unsafe_sent t (send fd t.buf ~pos:t.lo ~len:(length t)) ) ;; let sendto_nonblocking_no_sigpipe () = Or_error.map Bigstring.sendto_nonblocking_no_sigpipe ~f:(fun sendto -> fun t fd addr -> unsafe_sent t (sendto fd t.buf ~pos:t.lo ~len:(length t) addr) ) ;; let write_assume_fd_is_nonblocking t fd = let nwritten = Bigstring.write_assume_fd_is_nonblocking fd t.buf ~pos:t.lo ~len:(length t) in unsafe_advance t nwritten ;; let pwrite_assume_fd_is_nonblocking t fd ~offset = let nwritten = Bigstring.pwrite_assume_fd_is_nonblocking fd ~offset t.buf ~pos:t.lo ~len:(length t) in unsafe_advance t nwritten ;; module Unsafe = struct module Consume = struct (* copy of Consume with pos replaced by an unsafe version *) type src = Consume.src module To_string = struct include Consume.To_string let blit = unsafe_blit end module To_bigstring = struct include Consume.To_bigstring let blit = unsafe_blit end type ('a, 'd, 'w) t = ('a, 'd, 'w) Consume.t let uadv t n x = unsafe_advance t n; x let upos t = unsafe_buf_pos t ~pos:0 let tail_padded_fixed_string ~padding ~len t = uadv t len (Bigstring.get_tail_padded_fixed_string t.buf ~pos:(upos t) ~padding ~len ()) ;; let string = Consume.string let bigstring = Consume.bigstring let bin_prot = Consume.bin_prot open Bigstring let len = 1 let char t = uadv t len (bigstring_unsafe_get t.buf ~pos:(upos t)) let len = 2 let int16_be t = uadv t len (unsafe_get_int16_be t.buf ~pos:(upos t)) let int16_le t = uadv t len (unsafe_get_int16_le t.buf ~pos:(upos t)) let uint16_be t = uadv t len (unsafe_get_uint16_be t.buf ~pos:(upos t)) let uint16_le t = uadv t len (unsafe_get_uint16_le t.buf ~pos:(upos t)) let len = 4 let int32_be t = uadv t len (unsafe_get_int32_be t.buf ~pos:(upos t)) let int32_le t = uadv t len (unsafe_get_int32_le t.buf ~pos:(upos t)) let uint32_be t = uadv t len (unsafe_get_uint32_be t.buf ~pos:(upos t)) let uint32_le t = uadv t len (unsafe_get_uint32_le t.buf ~pos:(upos t)) let len = 8 let int64_be t = uadv t len (unsafe_get_int64_be_exn t.buf ~pos:(upos t)) let int64_le t = uadv t len (unsafe_get_int64_le_exn t.buf ~pos:(upos t)) let int64_t_be t = uadv t len (unsafe_get_int64_t_be t.buf ~pos:(upos t)) let int64_t_le t = uadv t len (unsafe_get_int64_t_le t.buf ~pos:(upos t)) let int64_be_trunc t = uadv t len (unsafe_get_int64_be_trunc t.buf ~pos:(upos t)) let int64_le_trunc t = uadv t len (unsafe_get_int64_le_trunc t.buf ~pos:(upos t)) let uint8 t = Char.to_int (char t) let int8 t = (uint8 t lsl (word_size - 9)) asr (word_size - 9) end module Fill = struct type ('a, 'd, 'w) t = ('a, 'd, 'w) Fill.t (* copy with unsafe pos *) let upos t _len = unsafe_buf_pos t ~pos:0 let uadv t n = unsafe_advance t n let tail_padded_fixed_string ~padding ~len t src = Bigstring.set_tail_padded_fixed_string ~padding ~len t.buf ~pos:(upos t len) src; uadv t len ;; let string ?str_pos:(src_pos = 0) ?len t src = let len = match len with Some l -> l | None -> String.length src - src_pos in Bigstring.From_string.blit ~src ~src_pos ~len ~dst:t.buf ~dst_pos:(upos t len); uadv t len ;; let bigstring ?str_pos:(src_pos = 0) ?len t src = let len = match len with Some l -> l | None -> Bigstring.length src - src_pos in Bigstring.blit ~src ~src_pos ~len ~dst:t.buf ~dst_pos:(upos t len); uadv t len ;; let bin_prot = Fill.bin_prot open Bigstring let len = 1 let char t c = bigstring_unsafe_set t.buf c ~pos:(upos t len); uadv t len let len = 2 let int16_be t i = unsafe_set_int16_be t.buf i ~pos:(upos t len); uadv t len let int16_le t i = unsafe_set_int16_le t.buf i ~pos:(upos t len); uadv t len let uint16_be t i = unsafe_set_uint16_be t.buf i ~pos:(upos t len); uadv t len let uint16_le t i = unsafe_set_uint16_le t.buf i ~pos:(upos t len); uadv t len let len = 4 let int32_be t i = unsafe_set_int32_be t.buf i ~pos:(upos t len); uadv t len let int32_le t i = unsafe_set_int32_le t.buf i ~pos:(upos t len); uadv t len let uint32_be t i = unsafe_set_uint32_be t.buf i ~pos:(upos t len); uadv t len let uint32_le t i = unsafe_set_uint32_le t.buf i ~pos:(upos t len); uadv t len let len = 8 let int64_be t i = unsafe_set_int64_be t.buf i ~pos:(upos t len); uadv t len let int64_le t i = unsafe_set_int64_le t.buf i ~pos:(upos t len); uadv t len let int64_t_be t i = unsafe_set_int64_t_be t.buf i ~pos:(upos t len); uadv t len let int64_t_le t i = unsafe_set_int64_t_le t.buf i ~pos:(upos t len); uadv t len (* Bigstring int8 accessors are slow C calls. Use the fast char primitive. *) let uint8 t i = char t (Char.unsafe_of_int i) let int8 t i = char t (Char.unsafe_of_int i) let int64_be_trunc t i = unsafe_set_int64_be t.buf i ~pos:(upos t len); uadv t len let int64_le_trunc t i = unsafe_set_int64_le t.buf i ~pos:(upos t len); uadv t len let decimal t i = uadv t (Itoa.unsafe_poke_decimal t ~pos:0 i) end module Peek = struct type src = Peek.src module To_string = struct include Peek.To_string let blit = unsafe_blit end module To_bigstring = struct include Peek.To_bigstring let blit = unsafe_blit end type ('a, 'd, 'w) t = ('a, 'd, 'w) Peek.t let upos = unsafe_buf_pos let tail_padded_fixed_string ~padding ~len t ~pos = Bigstring.get_tail_padded_fixed_string t.buf ~padding ~len ~pos:(upos t ~pos) () ;; let string ?str_pos:(dst_pos = 0) ?len t ~pos = let len = match len with None -> length t - pos | Some l -> l in let dst = String.create (len + dst_pos) in Bigstring.To_string.unsafe_blit ~src:t.buf ~src_pos:(upos t ~pos) ~len ~dst ~dst_pos; dst ;; let bigstring ?str_pos:(dst_pos = 0) ?len t ~pos = let len = match len with None -> length t - pos | Some l -> l in let dst = Bigstring.create (len + dst_pos) in Bigstring.unsafe_blit ~src:t.buf ~src_pos:(upos t ~pos) ~len ~dst ~dst_pos; dst ;; let bin_prot = Peek.bin_prot open Bigstring let char t ~pos = bigstring_unsafe_get t.buf ~pos:(upos t ~pos) let int16_be t ~pos = unsafe_get_int16_be t.buf ~pos:(upos t ~pos) let int16_le t ~pos = unsafe_get_int16_le t.buf ~pos:(upos t ~pos) let uint16_be t ~pos = unsafe_get_uint16_be t.buf ~pos:(upos t ~pos) let uint16_le t ~pos = unsafe_get_uint16_le t.buf ~pos:(upos t ~pos) let int32_be t ~pos = unsafe_get_int32_be t.buf ~pos:(upos t ~pos) let int32_le t ~pos = unsafe_get_int32_le t.buf ~pos:(upos t ~pos) let uint32_be t ~pos = unsafe_get_uint32_be t.buf ~pos:(upos t ~pos) let uint32_le t ~pos = unsafe_get_uint32_le t.buf ~pos:(upos t ~pos) let int64_be t ~pos = unsafe_get_int64_be_exn t.buf ~pos:(upos t ~pos) let int64_le t ~pos = unsafe_get_int64_le_exn t.buf ~pos:(upos t ~pos) let int64_t_be t ~pos = unsafe_get_int64_t_be t.buf ~pos:(upos t ~pos) let int64_t_le t ~pos = unsafe_get_int64_t_le t.buf ~pos:(upos t ~pos) let uint8 t ~pos = Char.to_int (char t ~pos) let int8 t ~pos = (uint8 t ~pos lsl (word_size - 9)) asr (word_size - 9) let int64_be_trunc t ~pos = unsafe_get_int64_be_trunc t.buf ~pos:(upos t ~pos) let int64_le_trunc t ~pos = unsafe_get_int64_le_trunc t.buf ~pos:(upos t ~pos) end module Poke = struct type ('a, 'd, 'w) t = ('a, 'd, 'w) Poke.t let upos = unsafe_buf_pos let tail_padded_fixed_string ~padding ~len t ~pos src = Bigstring.set_tail_padded_fixed_string ~padding ~len t.buf ~pos:(upos t ~pos) src ;; let string ?str_pos:(src_pos = 0) ?len t ~pos src = let len = match len with None -> String.length src - src_pos | Some l -> l in Bigstring.From_string.unsafe_blit ~src ~src_pos ~len ~dst:t.buf ~dst_pos:(upos t ~pos) ;; let bigstring ?str_pos:(src_pos = 0) ?len t ~pos src = let len = match len with None -> Bigstring.length src - src_pos | Some l -> l in Bigstring.unsafe_blit ~src ~src_pos ~len ~dst:t.buf ~dst_pos:(upos t ~pos) ;; let bin_prot = Poke.bin_prot open Bigstring let char t ~pos c = bigstring_unsafe_set t.buf ~pos:(upos t ~pos) c let int16_be t ~pos i = unsafe_set_int16_be t.buf ~pos:(upos t ~pos) i let int16_le t ~pos i = unsafe_set_int16_le t.buf ~pos:(upos t ~pos) i let uint16_be t ~pos i = unsafe_set_uint16_be t.buf ~pos:(upos t ~pos) i let uint16_le t ~pos i = unsafe_set_uint16_le t.buf ~pos:(upos t ~pos) i let int32_be t ~pos i = unsafe_set_int32_be t.buf ~pos:(upos t ~pos) i let int32_le t ~pos i = unsafe_set_int32_le t.buf ~pos:(upos t ~pos) i let uint32_be t ~pos i = unsafe_set_uint32_be t.buf ~pos:(upos t ~pos) i let uint32_le t ~pos i = unsafe_set_uint32_le t.buf ~pos:(upos t ~pos) i let int64_be t ~pos i = unsafe_set_int64_be t.buf ~pos:(upos t ~pos) i let int64_le t ~pos i = unsafe_set_int64_le t.buf ~pos:(upos t ~pos) i let int64_t_be t ~pos i = unsafe_set_int64_t_be t.buf ~pos:(upos t ~pos) i let int64_t_le t ~pos i = unsafe_set_int64_t_le t.buf ~pos:(upos t ~pos) i (* Bigstring int8 accessors are slow C calls. Use the fast char primitive. *) let uint8 t ~pos i = char t ~pos (Char.unsafe_of_int i) let int8 t ~pos i = char t ~pos (Char.unsafe_of_int i) let int64_be_trunc t ~pos i = unsafe_set_int64_be t.buf ~pos:(upos t ~pos) i let int64_le_trunc t ~pos i = unsafe_set_int64_le t.buf ~pos:(upos t ~pos) i let decimal = Itoa.unsafe_poke_decimal end end (* Minimal blit benchmarks. *) (* ┌────────────────────────────────────────────────────────┬────────────┬────────────┐ * │ Name │ Time/Run │ Percentage │ * ├────────────────────────────────────────────────────────┼────────────┼────────────┤ * │ [iobuf.ml:Blit tests] string blit:5 │ 15.30ns │ 1.11% │ * │ [iobuf.ml:Blit tests] string blit:10 │ 15.57ns │ 1.13% │ * │ [iobuf.ml:Blit tests] string blit:100 │ 19.26ns │ 1.39% │ * │ [iobuf.ml:Blit tests] string blit:1000 │ 47.83ns │ 3.46% │ * │ [iobuf.ml:Blit tests] string blit:10000 │ 197.90ns │ 14.32% │ * │ [iobuf.ml:Blit tests] Blit:5 │ 24.38ns │ 1.76% │ * │ [iobuf.ml:Blit tests] Blit:10 │ 26.88ns │ 1.94% │ * │ [iobuf.ml:Blit tests] Blit:100 │ 30.01ns │ 2.17% │ * │ [iobuf.ml:Blit tests] Blit:1000 │ 57.83ns │ 4.18% │ * │ [iobuf.ml:Blit tests] Blit:10000 │ 391.42ns │ 28.31% │ * │ [iobuf.ml:Blit tests] Blit_consume:5 │ 23.00ns │ 1.66% │ * │ [iobuf.ml:Blit tests] Blit_consume:10 │ 25.36ns │ 1.83% │ * │ [iobuf.ml:Blit tests] Blit_consume:100 │ 29.79ns │ 2.15% │ * │ [iobuf.ml:Blit tests] Blit_consume:1000 │ 58.93ns │ 4.26% │ * │ [iobuf.ml:Blit tests] Blit_consume:10000 │ 395.19ns │ 28.59% │ * │ [iobuf.ml:Blit tests] Blit_fill:5 │ 24.28ns │ 1.76% │ * │ [iobuf.ml:Blit tests] Blit_fill:10 │ 26.84ns │ 1.94% │ * │ [iobuf.ml:Blit tests] Blit_fill:100 │ 29.54ns │ 2.14% │ * │ [iobuf.ml:Blit tests] Blit_fill:1000 │ 57.05ns │ 4.13% │ * │ [iobuf.ml:Blit tests] Blit_fill:10000 │ 395.72ns │ 28.62% │ * │ [iobuf.ml:Blit tests] Blit_consume_and_fill:5 │ 25.43ns │ 1.84% │ * │ [iobuf.ml:Blit tests] Blit_consume_and_fill:10 │ 27.19ns │ 1.97% │ * │ [iobuf.ml:Blit tests] Blit_consume_and_fill:100 │ 30.96ns │ 2.24% │ * │ [iobuf.ml:Blit tests] Blit_consume_and_fill:1000 │ 58.38ns │ 4.22% │ * │ [iobuf.ml:Blit tests] Blit_consume_and_fill:10000 │ 383.62ns │ 27.75% │ * │ [iobuf.ml:Blit tests] Blit.unsafe_blit [overlap]:5 │ 14.25ns │ 1.03% │ * │ [iobuf.ml:Blit tests] Blit.unsafe_blit [overlap]:10 │ 16.92ns │ 1.23% │ * │ [iobuf.ml:Blit tests] Blit.unsafe_blit [overlap]:100 │ 37.17ns │ 2.70% │ * │ [iobuf.ml:Blit tests] Blit.unsafe_blit [overlap]:1000 │ 169.60ns │ 12.32% │ * │ [iobuf.ml:Blit tests] Blit.unsafe_blit [overlap]:10000 │ 1_377.01ns │ 100.00% │ * └────────────────────────────────────────────────────────┴────────────┴────────────┘ *) BENCH_MODULE "Blit tests" = struct let lengths = [5; 10; 100; 1000; 10_000] BENCH_INDEXED "string blit" len lengths = let buf = create ~len in let str = String.create len in (fun () -> Peek.To_string.blit ~src:buf ~dst:str ~src_pos:0 ~dst_pos:0 ~len) BENCH_INDEXED "Blit" len lengths = let src = create ~len in let dst = create ~len in (fun () -> Blit.blito () ~src ~dst) BENCH_INDEXED "Blit_consume" len lengths = let src = create ~len in let dst = create ~len in (fun () -> Blit_consume.blito () ~src ~dst; reset src) BENCH_INDEXED "Blit_fill" len lengths = let src = create ~len in let dst = create ~len in (fun () -> Blit_fill.blito () ~src ~dst; reset dst) BENCH_INDEXED "Blit_consume_and_fill" len lengths = let src = create ~len in let dst = create ~len in (fun () -> Blit_consume_and_fill.blito () ~src ~dst; reset src; reset dst) BENCH_INDEXED "Blit.unsafe_blit [overlap]" len lengths = let t = create ~len:(len + 1) in (fun () -> Blit.unsafe_blit ~src:t ~dst:t ~len ~src_pos:0 ~dst_pos:1) end BENCH_MODULE "Poke tests" = struct let offsets = List.init 9 ~f:Fn.id let iobuf = create ~len:100 (* We test at different offsets to see if various byte alignments have a significant effect on performance. *) BENCH_INDEXED "char" pos offsets = (fun () -> Poke.char iobuf ~pos 'a') BENCH_INDEXED "uint8" pos offsets = (fun () -> Poke.uint8 iobuf ~pos pos) BENCH_INDEXED "int8" pos offsets = (fun () -> Poke.int8 iobuf ~pos pos) BENCH_INDEXED "int16_be" pos offsets = (fun () -> Poke.int16_be iobuf ~pos pos) BENCH_INDEXED "int16_le" pos offsets = (fun () -> Poke.int16_le iobuf ~pos pos) BENCH_INDEXED "uint16_be" pos offsets = (fun () -> Poke.uint16_be iobuf ~pos pos) BENCH_INDEXED "uint16_le" pos offsets = (fun () -> Poke.uint16_le iobuf ~pos pos) BENCH_INDEXED "int32_be" pos offsets = (fun () -> Poke.int32_be iobuf ~pos pos) BENCH_INDEXED "int32_le" pos offsets = (fun () -> Poke.int32_le iobuf ~pos pos) BENCH_INDEXED "uint32_be" pos offsets = (fun () -> Poke.uint32_be iobuf ~pos pos) BENCH_INDEXED "uint32_le" pos offsets = (fun () -> Poke.uint32_le iobuf ~pos pos) BENCH_INDEXED "int64_be" pos offsets = (fun () -> Poke.int64_be iobuf ~pos pos) BENCH_INDEXED "int64_le" pos offsets = (fun () -> Poke.int64_le iobuf ~pos pos) end BENCH_MODULE "Peek tests" = struct let offsets = List.init 9 ~f:Fn.id let iobuf = of_string (String.make 100 '\000') BENCH_INDEXED "char" pos offsets = (fun () -> ignore (Peek.char iobuf ~pos)) BENCH_INDEXED "uint8" pos offsets = (fun () -> ignore (Peek.uint8 iobuf ~pos)) BENCH_INDEXED "int8" pos offsets = (fun () -> ignore (Peek.int8 iobuf ~pos)) BENCH_INDEXED "int16_be" pos offsets = (fun () -> ignore (Peek.int16_be iobuf ~pos)) BENCH_INDEXED "int16_le" pos offsets = (fun () -> ignore (Peek.int16_le iobuf ~pos)) BENCH_INDEXED "uint16_be" pos offsets = (fun () -> ignore (Peek.uint16_be iobuf ~pos)) BENCH_INDEXED "uint16_le" pos offsets = (fun () -> ignore (Peek.uint16_le iobuf ~pos)) BENCH_INDEXED "int32_be" pos offsets = (fun () -> ignore (Peek.int32_be iobuf ~pos)) BENCH_INDEXED "int32_le" pos offsets = (fun () -> ignore (Peek.int32_le iobuf ~pos)) BENCH_INDEXED "uint32_be" pos offsets = (fun () -> ignore (Peek.uint32_be iobuf ~pos)) BENCH_INDEXED "uint32_le" pos offsets = (fun () -> ignore (Peek.uint32_le iobuf ~pos)) BENCH_INDEXED "int64_be" pos offsets = (fun () -> ignore (Peek.int64_be iobuf ~pos)) BENCH_INDEXED "int64_le" pos offsets = (fun () -> ignore (Peek.int64_le iobuf ~pos)) end BENCH_MODULE "Fill.decimal tests" = struct (* Quantify the gain from our version of [Fill.decimal] over [Int.to_string]. *) let values = [ Int.min_value; Int.min_value + 1; -10_000; 0; 35; 1_000; 1_000_000; Int.max_value ] let iobuf = create ~len:32 BENCH_INDEXED "Fill.decimal" x values = (fun () -> reset iobuf; Fill.decimal iobuf x) BENCH_INDEXED "Unsafe.Fill.decimal" x values = (fun () -> reset iobuf; Unsafe.Fill.decimal iobuf x) BENCH_INDEXED "Unsafe.Fill.string Int.to_string" x values = (fun () -> reset iobuf; Fill.string iobuf (Int.to_string x)) end core-113.00.00/src/iobuf.mli000066400000000000000000000434641256461075500153700ustar00rootroot00000000000000(** A non-moving (in the GC sense) contiguous range of bytes, useful for I/O operations. An iobuf consists of: - bigstring - limits -- a subrange of the bigstring - window -- a subrange of the limits All iobuf operations are restricted to operate within the limits. Initially, the window of an iobuf is identical to the limits. A phantom type, "seek" permission, controls whether or not code is allowed to change the limits and window. With seek permission, the limits can be [narrow]ed, but can never be widened, and the window can be set to an arbitrary subrange of the limits. A phantom type controls whether code can read and write bytes in the bigstring (within the limits) or can only read them. To present a restricted view of an iobuf to a client, one can create a sub-iobuf or add a type constraint. *) open Core_kernel.Std open Iobuf_intf type nonrec seek = seek with sexp_of type nonrec no_seek = no_seek with sexp_of (** The first type parameter controls whether the iobuf can be written to. The second type parameter controls whether the window and limits can be changed. See the [Perms] module for information on how the first type parameter is used. To allow [no_seek] or [seek] access, a function's type uses [_] rather than [no_seek] as the type argument to [t]. Using [_] allows the function to be directly applied to either permission. Using a specific permission would require code to use coercion [:>]. *) type (-'data_perm_read_write, +'seek_permission) t with sexp_of include Invariant.S2 with type ('a, 'b) t := ('a, 'b) t (** {1 Creation} *) (** [create ~len] creates a new iobuf, backed by a bigstring of length [len], with the limits and window set to the entire bigstring. *) val create : len:int -> (_, _) t (** [of_bigstring bigstring ~pos ~len] returns an iobuf backed by [bigstring], with the window and limits specified starting at [pos] and of length [len]. *) val of_bigstring : ?pos:int (** default is [0] *) -> ?len:int (** default is [Bigstring.length bigstring - pos] *) -> Bigstring.t -> ([< read_write], _) t (** forbid [immutable] to prevent aliasing *) (** [of_string s] returns a new iobuf whose contents are [s]. *) val of_string : string -> (_, _) t (** [sub_shared t ~pos ~len] returns a new iobuf with limits and window set to the subrange of [t] specified by [pos] and [len]. [sub_shared] preserves data permissions, but allows arbitrary seek permissions on the resulting iobuf. *) val sub_shared : ?pos:int -> ?len:int -> ('d, _) t -> ('d, _) t (** [set_bounds_and_buffer ~src ~dst] copies bounds metadata (i.e., limits and window) and shallowly copies the buffer (data pointer) from [src] to [dst]. It does not access data, but does allow access through [dst]. This makes [dst] an alias of [src]. Because [set_bounds_and_buffer] creates an alias, we disallow immutable [src] and [dst] using [[> write]]. Otherwise, one of [src] or [dst] could be [read_write :> read] and the other [immutable :> read], which would allow to write the [immutable] alias's data through the [read_write] alias. [set_bounds_and_buffer] is typically used to allocate a frame iobuf only once. This frame can be updated repeatedly and handed to users, without further allocation. Only the most allocation-sensitive applications need this. *) val set_bounds_and_buffer : src : ([> write] as 'data, _) t -> dst : ('data, seek) t -> unit (** [set_bounds_and_buffer_sub ?pos ?len ~src ~dst ()] is a more efficient version of: [set_bounds_and_buffer ~src:(Iobuf.sub_shared ?pos ?len src) ~dst]. [set_bounds_and_buffer ~src ~dst] is not the same as [set_bounds_and_buffer_sub ~dst ~src ()] because the limits are narrowed in the latter case. *) val set_bounds_and_buffer_sub : ?pos:int -> ?len:int -> src : ([> write] as 'data, _) t -> dst : ('data, seek) t -> unit -> unit (** {1 Generalization} One may wonder why you'd want to call [no_seek], given that a cast is already possible, e.g. [t : (_, seek) t :> (_, no_seek) t]. It turns out that if you want to define some [f : (_, _) t -> unit] of your own, which can be conveniently applied to [seek] iobufs without the user having to cast [seek] up, you need this [no_seek] function. [read_only] is more of an historical convenience now that [read_write] is a polymorphic variant, as one can now explicitly specify the general type for an argument with something like [t : (_ perms, _) t :> (read, _) t]. *) val read_only : ([> read], 's) t -> (read, 's) t val no_seek : ('r, _) t -> ('r, no_seek) t (** {1 Accessors} *) (** [capacity t] returns the size of [t]'s limits subrange. The capacity of an iobuf can be reduced via [narrow]. *) val capacity : (_, _) t -> int (** [length t] returns the size of [t]'s window. *) val length : (_, _) t -> int (** [is_empty t] is [length t = 0]. *) val is_empty : (_, _) t -> bool (** {1 Changing the limits} *) (** [narrow t] sets [t]'s limits to the current window. *) val narrow : (_, seek) t -> unit (** [narrow_lo t] sets [t]'s lower limit to the beginning of the current window. *) val narrow_lo : (_, seek) t -> unit (** [narrow_hi t] sets [t]'s upper limit to the end of the current window. *) val narrow_hi : (_, seek) t -> unit (** {1 Changing the window} *) (** One can call [Lo_bound.window t] to get a snapshot of the lower bound of the window, and then later restore that snapshot with [Lo_bound.restore]. This is useful for speculatively parsing, and then rewinding when there isn't enough data to finish. Similarly for [Hi_bound.window] and [Lo_bound.restore]. Using a snapshot with a different iobuf, even a sub iobuf of the snapshotted one, has unspecified results. An exception may be raised, or a silent error may occur. However, the safety guarantees of the iobuf will not be violated, i.e., the attempt will not enlarge the limits of the subject iobuf. *) module type Bound = Bound with type ('d, 'w) iobuf := ('d, 'w) t module Lo_bound : Bound module Hi_bound : Bound (** [advance t amount] advances the lower bound of the window by [amount]. It is an error to advance past the upper bound of the window or the lower limit. *) val advance : (_, seek) t -> int -> unit (** [unsafe_advance] is like [advance] but with no bounds checking, so incorrect usage can easily cause segfaults. *) val unsafe_advance : (_, seek) t -> int -> unit (** [resize t] sets the length of [t]'s window, provided it does not exceed limits. *) val resize : (_, seek) t -> len:int -> unit (** [unsafe_resize] is like [resize] but with no bounds checking, so incorrect usage can easily cause segfaults. *) val unsafe_resize : (_, seek) t -> len:int -> unit (** [rewind t] sets the lower bound of the window to the lower limit. *) val rewind : (_, seek) t -> unit (** [reset t] sets the window to the limits. *) val reset : (_, seek) t -> unit (** [flip_lo t] sets the window to range from the lower limit to the lower bound of the old window. This is typically called after a series of [Fill]s, to reposition the window in preparation to [Consume] the newly written data. The bounded version narrows the effective limit. This can preserve some data near the limit, such as an hypothetical packet header, in the case of [bounded_flip_lo] or unfilled suffix of a buffer, in [bounded_flip_hi]. *) val flip_lo : (_, seek) t -> unit val bounded_flip_lo : (_, seek) t -> Lo_bound.t -> unit (** [compact t] copies data from the window to the lower limit of the iobuf and sets the window to range from the end of the copied data to the upper limit. This is typically called after a series of [Consume]s to save unread data and prepare for the next series of [Fill]s and [flip_lo]. *) val compact : (read_write, seek) t -> unit val bounded_compact : (read_write, seek) t -> Lo_bound.t -> Hi_bound.t -> unit (** [flip_hi t] sets the window to range from the the upper bound of the current window to the upper limit. This operation is dual to [flip_lo] and is typically called when the data in the current (narrowed) window has been processed and the window needs to be positioned over the remaining data in the buffer. For example: {[ (* ... determine initial_data_len ... *) Iobuf.resize buf ~len:initial_data_len; (* ... and process initial data ... *) Iobuf.flip_hi buf; ]} Now the window of [buf] ranges over the remainder of the data. *) val flip_hi : (_, seek) t -> unit val bounded_flip_hi : (_, seek) t -> Hi_bound.t -> unit (** [protect_window_and_bounds t ~f] applies [f] to [t] and restores [t]'s bounds afterwards. *) val protect_window_and_bounds : ('rw, no_seek) t -> f:(('rw, seek) t -> 'a) -> 'a (** {1 Getting and setting data} *) (** "consume" and "fill" functions access data at the lower bound of the window and advance lower bound of the window. "peek" and "poke" functions access data but do not advance the window. *) (** [to_string t] returns the bytes in [t] as a string. It does not alter the window. *) val to_string : ?len:int -> ([> read], _) t -> string (** [to_string_hum t] produces a readable, multi-line representation of an iobuf. [bounds] defaults to [`Limits] and determines how much of the contents are shown. *) val to_string_hum : ?bounds:[`Window | `Limits | `Whole] -> ([> read], _) t -> string (** [Consume.string t ~len] reads [len] characters (all, by default) from [t] into a new string and advances the lower bound of the window accordingly. [Consume.bin_prot X.bin_read_t t] returns the initial [X.t] in [t], advancing past the bytes read. *) module Consume : sig (** [To_string.blito ~src ~dst ~dst_pos ~src_len ()] reads [src_len] bytes from [src], advancing [src]'s window accordingly, and writes them into [dst] starting at [dst_pos]. By default [dst_pos = 0] and [src_len = length src]. It is an error if [dst_pos] and [src_len] don't specify a valid region of [dst] or [src_len > length src]. *) type src = (read, seek) t module To_string : Consuming_blit with type src := src with type dst := string module To_bigstring : Consuming_blit with type src := src with type dst := Bigstring.t include Accessors with type ('a, 'r, 's) t = ([> read] as 'r, seek) t -> 'a with type 'a bin_prot := 'a Bin_prot.Type_class.reader end (** [Fill.bin_prot X.bin_write_t t x] writes [x] to [t] in bin-prot form, advancing past the bytes written. *) module Fill : sig include Accessors with type ('a, 'd, 'w) t = (read_write, seek) t -> 'a -> unit with type 'a bin_prot := 'a Bin_prot.Type_class.writer (* [decimal t int] is equivalent to [Iobuf.Fill.string t (Int.to_string int)], but with improved efficiency and no intermediate allocation. In other words: It fills the decimal representation of [int] to [t]. [t] is advanced by the number of characters written and no terminator is added. If sufficient space is not available [decimal] will raise. *) val decimal : (int, _, _) t end (** [Peek] and [Poke] functions access a value at [pos] from the lower bound of the window and do not advance. [Peek.bin_prot X.bin_read_t t] returns the initial [X.t] in [t] without advancing. Following the [bin_prot] protocol, the representation of [x] is [X.bin_size_t x] bytes long. [Peek.], [Poke.], [Consume.], and [Fill.bin_prot] do not add any size prefix or other framing to the [bin_prot] representation. *) module Peek : sig (** Similar to [Consume.To_*], but do not advance the buffer. *) type src = (read, no_seek) t module To_string : Blit.S_distinct with type src := src with type dst := string module To_bigstring : Blit.S_distinct with type src := src with type dst := Bigstring.t include Accessors with type ('a, 'd, 'w) t = ('d, 'w) t -> pos:int -> 'a with type 'a bin_prot := 'a Bin_prot.Type_class.reader end (** [Poke.bin_prot X.bin_write_t t x] writes [x] to the beginning of [t] in binary form without advancing. You can use [X.bin_size_t] to tell how long it was. [X.bin_write_t] is only allowed to write that portion of the buffer to which you have access. *) module Poke : sig (** [decimal t ~pos i] returns the number of bytes written at [pos]. *) val decimal : (read_write, 'w) t -> pos:int -> int -> int include Accessors with type ('a, 'd, 'w) t = (read_write, 'w) t -> pos:int -> 'a -> unit with type 'a bin_prot := 'a Bin_prot.Type_class.writer end (** [Unsafe] has submodules that are like their corresponding module, except with no range checks. Hence, mistaken uses can cause segfaults. Be careful! *) module Unsafe : sig module Consume : module type of Consume module Fill : module type of Fill module Peek : module type of Peek module Poke : module type of Poke end val crc32 : ([> read], _) t -> Int63.t (** [fill_bin_prot] writes a bin-prot value to the lower bound of the window, prefixed by its length, and advances by the amount written. [fill_bin_prot] returns an error if the window is too small to write the value. [consume_bin_prot t reader] reads a bin-prot value from the lower bound of the window, which should have been written using [fill_bin_prot], and advances the window by the amount read. [consume_bin_prot] returns an error if there is not a complete message in the window and in that case the window is left unchanged. Don't use these without a good reason, as they are incompatible with similar functions in [Reader] and [Writer]. They use a 4-byte length rather than an 8-byte length. *) val fill_bin_prot : (read_write, seek) t -> 'a Bin_prot.Type_class.writer -> 'a -> unit Or_error.t val consume_bin_prot : ([> read] , seek) t -> 'a Bin_prot.Type_class.reader -> 'a Or_error.t (** [Blit] copies between iobufs and advances neither [src] nor [dst]. *) module Blit : sig type 'rw t_no_seek = ('rw, no_seek) t include Blit.S_permissions with type 'rw t := 'rw t_no_seek (** Override types of [sub] and [subo] to allow return type to have [seek] as needed. *) val sub : ([> read], no_seek) t -> pos : int -> len : int -> (_, _) t val subo : ?pos : int -> ?len : int -> ([> read], no_seek) t -> (_, _) t end (** [Blit_consume] copies between iobufs and advances [src] but does not advance [dst]. *) module Blit_consume : sig val blit : src : ([> read], seek) t -> dst : ([> write], no_seek) t -> dst_pos : int -> len : int -> unit val blito : src : ([> read], seek) t -> ?src_len : int -> dst : ([> write], no_seek) t -> ?dst_pos : int -> unit -> unit val unsafe_blit : src : ([> read], seek) t -> dst : ([> write], no_seek) t -> dst_pos : int -> len : int -> unit val sub : ([> read], seek) t -> len : int -> (_, _) t val subo : ?len : int -> ([> read], seek) t -> (_, _) t end (** [Blit_fill] copies between iobufs and advances [dst] but does not advance [src]. *) module Blit_fill : sig val blit : src : ([> read], no_seek) t -> src_pos : int -> dst : ([> write], seek) t -> len : int -> unit val blito : src : ([> read], no_seek) t -> ?src_pos : int -> ?src_len : int -> dst : ([> write], seek) t -> unit -> unit val unsafe_blit : src : ([> read], no_seek) t -> src_pos : int -> dst : ([> write], seek) t -> len : int -> unit end (** [Blit_consume_and_fill] copies between iobufs and advances both [src] and [dst]. *) module Blit_consume_and_fill : sig val blit : src : ([> read], seek) t -> dst : ([> write], seek) t -> len : int -> unit val blito : src : ([> read], seek) t -> ?src_len : int -> dst : ([> write], seek) t -> unit -> unit val unsafe_blit : src : ([> read], seek) t -> dst : ([> write], seek) t -> len : int -> unit end (** {1 I/O} *) (** [Iobuf] has analogs of various [Bigstring] functions. These analogs advance by the amount written/read. *) val read_assume_fd_is_nonblocking : (read_write, seek) t -> Unix.File_descr.t -> Syscall_result.Unit.t val pread_assume_fd_is_nonblocking : (read_write, seek) t -> Unix.File_descr.t -> offset:int -> unit val recvfrom_assume_fd_is_nonblocking : (read_write, seek) t -> Unix.File_descr.t -> Unix.sockaddr val recvmmsg_assume_fd_is_nonblocking : (Unix.File_descr.t -> ?count:int -> ?srcs:Unix.sockaddr array -> (read_write, seek) t array -> Unix.Syscall_result.Int.t) Or_error.t val recvmmsg_assume_fd_is_nonblocking_no_options : (Unix.File_descr.t -> count:int -> (read_write, seek) t array -> Unix.Syscall_result.Int.t) Or_error.t val send_nonblocking_no_sigpipe : unit -> (([> read], seek) t -> Unix.File_descr.t -> Unix.Syscall_result.Unit.t ) Or_error.t val sendto_nonblocking_no_sigpipe : unit -> (([> read], seek) t -> Unix.File_descr.t -> Unix.sockaddr -> Unix.Syscall_result.Unit.t ) Or_error.t val write_assume_fd_is_nonblocking : ([> read], seek) t -> Unix.File_descr.t -> unit val pwrite_assume_fd_is_nonblocking : ([> read], seek) t -> Unix.File_descr.t -> offset:int -> unit (** {1 Expert} *) (** The [Expert] module is for building efficient out-of-module [Iobuf] abstractions. They will not allocate, and are mainly here to assist in building low-cost syscall wrappers. One must be careful to avoid writing out of the limits (between [lo_min] and [hi_max]) of the [buf]. Doing so would violate the invariants of the parent [Iobuf]. *) module Expert: sig val buf: (_, _) t -> Bigstring.t val hi_max: (_, _) t -> int val hi: (_, _) t -> int val lo: (_, _) t -> int val lo_min: (_, _) t -> int end core-113.00.00/src/iobuf_debug.ml000066400000000000000000001235541256461075500163640ustar00rootroot00000000000000open Core_kernel.Std module Unix = Core_unix let concat = String.concat let log string a sexp_of_a = Printf.eprintf "%s\n%!" (Sexp.to_string_hum (<:sexp_of< string * a >> (string, a))); ;; module Make () = struct let check_invariant = ref true let show_messages = ref true open Iobuf type nonrec ('d, 'w) t = ('d, 'w) t with sexp_of type nonrec seek = seek with sexp_of type nonrec no_seek = no_seek with sexp_of module type Bound = Bound let invariant = invariant let debug name ts arg sexp_of_arg sexp_of_result f = let prefix = "Iobuf." in if !show_messages then log (concat [ prefix; name ]) arg sexp_of_arg; if !check_invariant then List.iter ts ~f:(invariant ignore ignore); let result_or_exn = Result.try_with f in if !show_messages then log (concat [ prefix; name; " result" ]) result_or_exn (<:sexp_of< (result, exn) Result.t >>); if !check_invariant then List.iter ts ~f:(invariant ignore ignore); Result.ok_exn result_or_exn; ;; let debug_blit name ~src ~dst a sexp_of_a sexp_of_ret f = debug name [src] (dst, a) <:sexp_of< (_, _) t * a >> <:sexp_of< ret >> (fun () -> (* Check dst's invariant separately because it has a different type. *) let finally () = if !check_invariant then invariant ignore ignore dst in finally (); protect ~finally ~f) ;; let read_only t = debug "read_only" [t] () sexp_of_unit <:sexp_of< (_, _) t >> (fun () -> read_only t) let no_seek t = debug "no_seek" [t] () sexp_of_unit <:sexp_of< (_, _) t >> (fun () -> no_seek t) let create ~len = debug "create" [] (`len len) (<:sexp_of< [ `len of int ] >>) (<:sexp_of< (_, _) t >>) (fun () -> let t = create ~len in if !check_invariant then invariant ignore ignore t; t) ;; let capacity t = debug "capacity" [t] t <:sexp_of< (_, _) t >> sexp_of_int (fun () -> capacity t) ;; let of_bigstring ?pos ?len bigstring = debug "of_bigstring" [] (`pos pos, `len len, `bigstring_len (Bigstring.length bigstring)) (<:sexp_of< ([ `pos of int option ] * [ `len of int option ] * [ `bigstring_len of int ]) >>) (<:sexp_of< (_, _) t >>) (fun () -> let t = of_bigstring ?pos ?len bigstring in if !check_invariant then invariant ignore ignore t; t) ;; let length t = debug "length" [t] t <:sexp_of< (_, _) t >> sexp_of_int (fun () -> length t) ;; let is_empty t = debug "is_empty" [t] t <:sexp_of< (_, _) t >> sexp_of_bool (fun () -> is_empty t) ;; module Bound (Bound : Bound) (Name : sig val name : string end) = struct type t = Bound.t with sexp_of let window iobuf = debug (Name.name ^ ".window") [iobuf] () sexp_of_unit Bound.sexp_of_t (fun () -> Bound.window iobuf) let restore t iobuf = debug (Name.name ^ ".restore") [iobuf] t Bound.sexp_of_t sexp_of_unit (fun () -> Bound.restore t iobuf) let limit iobuf = debug (Name.name ^ ".limit") [iobuf] () sexp_of_unit Bound.sexp_of_t (fun () -> Bound.limit iobuf) end module Lo_bound = Bound (Lo_bound) (struct let name = "Lo_bound" end) module Hi_bound = Bound (Hi_bound) (struct let name = "Hi_bound" end) let rewind t = debug "rewind" [t] t <:sexp_of< (_, _) t >> sexp_of_unit (fun () -> rewind t) ;; let reset t = debug "reset" [t] t <:sexp_of< (_, _) t >> sexp_of_unit (fun () -> reset t) ;; let flip_lo t = debug "flip_lo" [t] t <:sexp_of< (_, _) t >> sexp_of_unit (fun () -> flip_lo t) ;; let bounded_flip_lo t lo_min = debug "bounded_flip_lo" [t] lo_min Lo_bound.sexp_of_t sexp_of_unit (fun () -> bounded_flip_lo t lo_min) ;; let compact t = debug "compact" [t] t <:sexp_of< (_, _) t >> sexp_of_unit (fun () -> compact t) ;; let bounded_compact t lo_min hi_max = debug "bounded_compact" [t] (lo_min, hi_max) <:sexp_of< Lo_bound.t * Hi_bound.t >> sexp_of_unit (fun () -> bounded_compact t lo_min hi_max) let flip_hi t = debug "flip_hi" [t] () <:sexp_of< unit >> sexp_of_unit (fun () -> flip_hi t) ;; let bounded_flip_hi t hi_max = debug "bounded_flip_hi" [t] hi_max Hi_bound.sexp_of_t sexp_of_unit (fun () -> bounded_flip_hi t hi_max) ;; let sub_shared ?pos ?len t = debug "sub_shared" [t] (`pos pos, `len len) <:sexp_of< [ `pos of int option ] * [ `len of int option ] >> <:sexp_of< (_, _) t >> (fun () -> sub_shared ?pos ?len t) ;; let set_bounds_and_buffer_sub ?pos ?len ~src ~dst () = debug "sub" [src] (`pos pos, `len len) <:sexp_of< [ `pos of int option ] * [ `len of int option ] >> sexp_of_unit (fun () -> set_bounds_and_buffer_sub ?pos ?len ~src ~dst ()) ;; let set_bounds_and_buffer ~src ~dst = debug "copy" [src] src <:sexp_of< (_, _) t >> sexp_of_unit (fun () -> set_bounds_and_buffer ~src ~dst) ;; let narrow t = debug "narrow" [t] t <:sexp_of< (_, _) t >> sexp_of_unit (fun () -> narrow t) ;; let narrow_lo t = debug "narrow_lo" [t] t <:sexp_of< (_, _) t >> sexp_of_unit (fun () -> narrow_lo t) ;; let narrow_hi t = debug "narrow_hi" [t] t <:sexp_of< (_, _) t >> sexp_of_unit (fun () -> narrow_hi t) ;; let resize t ~len = debug "resize" [t] (`len len) <:sexp_of< [ `len of int ] >> sexp_of_unit (fun () -> resize t ~len) ;; let unsafe_resize t ~len = debug "unsafe_resize" [t] (`len len) <:sexp_of< [ `len of int ] >> sexp_of_unit (fun () -> unsafe_resize t ~len) ;; let protect_window_and_bounds t ~f = debug "protect_window_and_bounds" [t] t <:sexp_of< (_, _) t >> <:sexp_of< _ >> (fun () -> protect_window_and_bounds t ~f) ;; let of_string s = debug "of_string" [] s <:sexp_of< string >> <:sexp_of< (_, _) t >> (fun () -> let t = of_string s in if !check_invariant then invariant ignore ignore t; t) ;; let to_string ?len t = debug "to_string" [t] (`len len) <:sexp_of< [ `len of int option ] >> <:sexp_of< string >> (fun () -> to_string ?len t) ;; let to_string_hum ?bounds t = debug "to_string_hum" [t] (`bounds bounds) <:sexp_of<[`bounds of [`Window|`Limits|`Whole] option]>> <:sexp_of> (fun () -> to_string_hum ?bounds t) let advance t i = debug "advance" [t] i sexp_of_int sexp_of_unit (fun () -> advance t i) let unsafe_advance t i = debug "unsafe_advance" [t] i sexp_of_int sexp_of_unit (fun () -> unsafe_advance t i) module Consume_blit_debug = struct module type To = Iobuf_intf.Consuming_blit with type src := Consume.src module To (To : sig include To val sexp_of_dst : dst -> Sexp.t val module_name : string end) = struct let blito ~src ?src_len ~dst ?dst_pos () = debug (To.module_name ^ ".blito") [src] (src_len, dst, dst_pos) <:sexp_of< int option * To.dst * int option >> sexp_of_unit (To.blito ~src ?src_len ~dst ?dst_pos) let blit ~src ~dst ~dst_pos ~len = debug (To.module_name ^ ".blit") [src] (dst, dst_pos, len) <:sexp_of< To.dst * int * int >> sexp_of_unit (fun () -> To.blit ~src ~len ~dst ~dst_pos) let unsafe_blit ~src ~dst ~dst_pos ~len = debug (To.module_name ^ ".unsafe_blit") [src] (dst, dst_pos, len) <:sexp_of< To.dst * int * int >> sexp_of_unit (fun () -> To.unsafe_blit ~src ~len ~dst ~dst_pos) let sub src ~len = debug (To.module_name ^ ".sub") [src] len <:sexp_of< int >> To.sexp_of_dst (fun () -> To.sub src ~len) let subo ?len src = debug (To.module_name ^ ".subo") [src] len <:sexp_of< int option >> To.sexp_of_dst (fun () -> To.subo ?len src) end module Make (C : sig module To_string : To with type dst := string module To_bigstring : To with type dst := bigstring val module_name : string end) = struct module To_string = To (struct type dst = string with sexp_of include C.To_string let module_name = C.module_name ^ ".To_string" end) module To_bigstring = To (struct type dst = bigstring with sexp_of include C.To_bigstring let module_name = C.module_name ^ ".To_bigstring" end) type src = Consume.src end end module Consume = struct let d name f sexp_of_result t = debug ("Consume." ^ name) [t] t <:sexp_of< (_, _) t >> sexp_of_result (fun () -> f t) ;; open Consume include Consume_blit_debug.Make (struct include Consume let module_name = "Consume" end) type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char t = d "char" char sexp_of_char t let int8 t = d "int8" int8 sexp_of_int t let int16_be t = d "int16_be" int16_be sexp_of_int t let int16_le t = d "int16_le" int16_le sexp_of_int t let int32_be t = d "int32_be" int32_be sexp_of_int t let int32_le t = d "int32_le" int32_le sexp_of_int t let uint8 t = d "uint8" uint8 sexp_of_int t let uint16_be t = d "uint16_be" uint16_be sexp_of_int t let uint16_le t = d "uint16_le" uint16_le sexp_of_int t let uint32_be t = d "uint32_be" uint32_be sexp_of_int t let uint32_le t = d "uint32_le" uint32_le sexp_of_int t let int64_be t = d "int64_be" int64_be sexp_of_int t let int64_le t = d "int64_le" int64_le sexp_of_int t let int64_t_be t = d "int64_t_be" int64_t_be sexp_of_int64 t let int64_t_le t = d "int64_t_le" int64_t_le sexp_of_int64 t let int64_be_trunc t = d "int64_be_trunc" int64_be_trunc sexp_of_int t let int64_le_trunc t = d "int64_le_trunc" int64_le_trunc sexp_of_int t let tail_padded_fixed_string ~padding ~len t = debug "Consume.tail_padded_fixed_string" [t] (`padding padding, `len len) <:sexp_of< [ `padding of char ] * [ `len of int ] >> sexp_of_string (fun () -> tail_padded_fixed_string ~padding ~len t) let string ?str_pos ?len t = debug "Consume.string" [t] (`str_pos str_pos, `len len) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] >> sexp_of_string (fun () -> string ?str_pos ?len t) let bigstring ?str_pos ?len t = debug "Consume.bigstring" [t] (`str_pos str_pos, `len len) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] >> sexp_of_bigstring (fun () -> bigstring ?str_pos ?len t) let bin_prot reader t = debug "Consume.bin_prot" [t] () <:sexp_of< unit >> <:sexp_of< _ >> (fun () -> bin_prot reader t) end module Fill = struct let d name f sexp_of_arg t arg = debug ("Fill." ^ name) [t] arg sexp_of_arg sexp_of_unit (fun () -> f t arg) ;; open Fill type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char t = d "char" char sexp_of_char t let int8 t = d "int8" int8 sexp_of_int t let int16_be t = d "int16_be" int16_be sexp_of_int t let int16_le t = d "int16_le" int16_le sexp_of_int t let int32_be t = d "int32_be" int32_be sexp_of_int t let int32_le t = d "int32_le" int32_le sexp_of_int t let uint8 t = d "uint8" uint8 sexp_of_int t let uint16_be t = d "uint16_be" uint16_be sexp_of_int t let uint16_le t = d "uint16_le" uint16_le sexp_of_int t let uint32_be t = d "uint32_be" uint32_be sexp_of_int t let uint32_le t = d "uint32_le" uint32_le sexp_of_int t let int64_be t = d "int64_be" int64_be sexp_of_int t let int64_le t = d "int64_le" int64_le sexp_of_int t let int64_t_be t = d "int64_t_be" int64_t_be sexp_of_int64 t let int64_t_le t = d "int64_t_le" int64_t_le sexp_of_int64 t let int64_be_trunc t = d "int64_be_trunc" int64_be_trunc sexp_of_int t let int64_le_trunc t = d "int64_le_trunc" int64_le_trunc sexp_of_int t let decimal t = d "decimal" decimal sexp_of_int t let tail_padded_fixed_string ~padding ~len t str = debug "Fill.tail_padded_fixed_string" [t] (`padding padding, `len len, str) <:sexp_of< [ `padding of char ] * [ `len of int ] * string >> sexp_of_unit (fun () -> tail_padded_fixed_string ~padding ~len t str) let string ?str_pos ?len t str = debug "Fill.string" [t] (`str_pos str_pos, `len len, str) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * string >> sexp_of_unit (fun () -> string ?str_pos ?len t str) let bigstring ?str_pos ?len t str = debug "Fill.bigstring" [t] (`str_pos str_pos, `len len, str) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * bigstring >> sexp_of_unit (fun () -> bigstring ?str_pos ?len t str) let bin_prot writer t a = debug "Fill.bin_prot" [t] () <:sexp_of< _ >> <:sexp_of< unit >> (fun () -> bin_prot writer t a) end module Peek_blit_debug = struct module type To = Core_kernel.Std.Blit.S_distinct with type src := Peek.src module To (To : sig include To val sexp_of_dst : dst -> Sexp.t val module_name : string end) = struct let blito ~src ?src_pos ?src_len ~dst ?dst_pos () = debug (To.module_name ^ ".blito") [src] (src_pos, src_len, dst, dst_pos) <:sexp_of< int option * int option * To.dst * int option >> sexp_of_unit (To.blito ~src ?src_pos ?src_len ~dst ?dst_pos) let blit ~src ~src_pos ~dst ~dst_pos ~len = debug (To.module_name ^ ".blit") [src] (src_pos, dst, dst_pos, len) <:sexp_of< int * To.dst * int * int >> sexp_of_unit (fun () -> To.blit ~src ~src_pos ~dst ~dst_pos ~len) let unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len = debug (To.module_name ^ ".unsafe_blit") [src] (src_pos, dst, dst_pos, len) <:sexp_of< int * To.dst * int * int >> sexp_of_unit (fun () -> To.unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len) let sub src ~pos ~len = debug (To.module_name ^ ".sub") [src] (pos, len) <:sexp_of< int * int >> To.sexp_of_dst (fun () -> To.sub src ~pos ~len) let subo ?pos ?len src = debug (To.module_name ^ ".subo") [src] (pos, len) <:sexp_of< int option * int option >> To.sexp_of_dst (fun () -> To.subo ?pos ?len src) end module Make (C : sig module To_string : To with type dst := string module To_bigstring : To with type dst := bigstring val module_name : string end) = struct type src = Peek.src module To_string = To (struct type dst = string with sexp_of include C.To_string let module_name = C.module_name ^ ".To_string" end) module To_bigstring = To (struct type dst = bigstring with sexp_of include C.To_bigstring let module_name = C.module_name ^ ".To_bigstring" end) end end module Peek = struct let d name f sexp_of_result t ~pos = debug ("Peek." ^ name) [t] (`pos pos) <:sexp_of< [ `pos of int ] >> sexp_of_result (fun () -> f t ~pos) ;; open Peek include Peek_blit_debug.Make (struct include Peek let module_name = "Peek" end) type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char t = d "char" char sexp_of_char t let int8 t = d "int8" int8 sexp_of_int t let int16_be t = d "int16_be" int16_be sexp_of_int t let int16_le t = d "int16_le" int16_le sexp_of_int t let int32_be t = d "int32_be" int32_be sexp_of_int t let int32_le t = d "int32_le" int32_le sexp_of_int t let uint8 t = d "uint8" uint8 sexp_of_int t let uint16_be t = d "uint16_be" uint16_be sexp_of_int t let uint16_le t = d "uint16_le" uint16_le sexp_of_int t let uint32_be t = d "uint32_be" uint32_be sexp_of_int t let uint32_le t = d "uint32_le" uint32_le sexp_of_int t let int64_be t = d "int64_be" int64_be sexp_of_int t let int64_le t = d "int64_le" int64_le sexp_of_int t let int64_t_be t = d "int64_t_be" int64_t_be sexp_of_int64 t let int64_t_le t = d "int64_t_le" int64_t_le sexp_of_int64 t let int64_be_trunc t = d "int64_be_trunc" int64_be_trunc sexp_of_int t let int64_le_trunc t = d "int64_le_trunc" int64_le_trunc sexp_of_int t let tail_padded_fixed_string ~padding ~len t ~pos = debug "Peek.tail_padded_fixed_string" [t] (`padding padding, `len len, `pos pos) <:sexp_of< [ `padding of char ] * [ `len of int ] * [ `pos of int ] >> sexp_of_string (fun () -> tail_padded_fixed_string ~padding ~len t ~pos) let string ?str_pos ?len t ~pos = debug "Peek.string" [t] (`str_pos str_pos, `len len, `pos pos) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * [ `pos of int ] >> sexp_of_string (fun () -> string ?str_pos ?len t ~pos) let bigstring ?str_pos ?len t ~pos = debug "Peek.bigstring" [t] (`str_pos str_pos, `len len, `pos pos) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * [ `pos of int ] >> sexp_of_bigstring (fun () -> bigstring ?str_pos ?len t ~pos) let bin_prot reader t ~pos = debug "Consume.bin_prot" [t] (`pos pos) <:sexp_of< [ `pos of int ] >> <:sexp_of< _ >> (fun () -> bin_prot reader t ~pos) end module Poke = struct let d name f sexp_of_arg t ~pos arg = debug ("Poke." ^ name) [t] (`pos pos, arg) (Tuple.T2.sexp_of_t <:sexp_of< [ `pos of int ] >> sexp_of_arg) sexp_of_unit (fun () -> f t ~pos arg) ;; open Poke type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char t = d "char" char sexp_of_char t let int8 t = d "int8" int8 sexp_of_int t let int16_be t = d "int16_be" int16_be sexp_of_int t let int16_le t = d "int16_le" int16_le sexp_of_int t let int32_be t = d "int32_be" int32_be sexp_of_int t let int32_le t = d "int32_le" int32_le sexp_of_int t let uint8 t = d "uint8" uint8 sexp_of_int t let uint16_be t = d "uint16_be" uint16_be sexp_of_int t let uint16_le t = d "uint16_le" uint16_le sexp_of_int t let uint32_be t = d "uint32_be" uint32_be sexp_of_int t let uint32_le t = d "uint32_le" uint32_le sexp_of_int t let int64_be t = d "int64_be" int64_be sexp_of_int t let int64_le t = d "int64_le" int64_le sexp_of_int t let int64_t_be t = d "int64_t_be" int64_t_be sexp_of_int64 t let int64_t_le t = d "int64_t_le" int64_t_le sexp_of_int64 t let int64_be_trunc t = d "int64_be_trunc" int64_be_trunc sexp_of_int t let int64_le_trunc t = d "int64_le_trunc" int64_le_trunc sexp_of_int t let decimal t ~pos arg = debug "Poke.decimal" [t] (`pos pos, arg) <:sexp_of< [ `pos of int ] * int >> sexp_of_int (fun () -> decimal t ~pos arg) let tail_padded_fixed_string ~padding ~len t ~pos str = debug "Poke.tail_padded_fixed_string" [t] (`padding padding, `len len, `pos pos, str) <:sexp_of< [ `padding of char ] * [ `len of int ] * [ `pos of int ] * string >> sexp_of_unit (fun () -> tail_padded_fixed_string ~padding ~len t ~pos str) let string ?str_pos ?len t ~pos str = debug "Poke.string" [t] (`str_pos str_pos, `len len, `pos pos, str) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * [ `pos of int ] * string >> sexp_of_unit (fun () -> string ?str_pos ?len t ~pos str) let bigstring ?str_pos ?len t ~pos str = debug "Poke.bigstring" [t] (`str_pos str_pos, `len len, `pos pos, str) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * [ `pos of int ] * bigstring >> sexp_of_unit (fun () -> bigstring ?str_pos ?len t ~pos str) let bin_prot writer t ~pos a = debug "Poke.bin_prot" [t] (`pos pos) <:sexp_of< [ `pos of int ] >> <:sexp_of< unit >> (fun () -> bin_prot writer t a ~pos) end let crc32 t = debug "crc32" [t] t <:sexp_of< (_, _) t >> <:sexp_of< Int63.Hex.t >> (fun () -> crc32 t) let consume_bin_prot t r = debug "consume_bin_prot" [t] t <:sexp_of< (_, _) t >> <:sexp_of< _ Or_error.t >> (fun () -> consume_bin_prot t r) ;; let fill_bin_prot t w a = debug "fill_bin_prot" [t] t <:sexp_of< (_, _) t >> <:sexp_of< unit Or_error.t >> (fun () -> fill_bin_prot t w a) ;; module Blit = struct open Blit type 'rw t_no_seek = 'rw Blit.t_no_seek let unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len = debug_blit "Blit.unsafe_blit" ~src ~dst (`src_pos src_pos, `dst_pos dst_pos, `len len) (<:sexp_of< [`src_pos of int] * [`dst_pos of int] * [`len of int] >>) (<:sexp_of< unit >>) (fun () -> unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len) ;; let blit ~src ~src_pos ~dst ~dst_pos ~len = debug_blit "Blit.blit" ~src ~dst (`src_pos src_pos, `dst_pos dst_pos, `len len) (<:sexp_of< [`src_pos of int] * [`dst_pos of int] * [`len of int] >>) (<:sexp_of< unit >>) (fun () -> blit ~src ~src_pos ~dst ~dst_pos ~len) ;; let blito ~src ?src_pos ?src_len ~dst ?dst_pos () = debug_blit "Blit.blito" ~src ~dst (`src_pos src_pos, `src_len src_len, `dst_pos dst_pos) (<:sexp_of< [`src_pos of int option] * [`src_len of int option] * [`dst_pos of int option] >>) (<:sexp_of< unit >>) (fun () -> blito ~src ?src_pos ?src_len ~dst ?dst_pos ()) ;; let sub t ~pos ~len = debug "Blit.sub" [t] (`pos pos, `len len) (<:sexp_of< [`pos of int] * [`len of int] >>) (<:sexp_of< (_, _) t >>) (fun () -> let t = sub t ~pos ~len in if !check_invariant then invariant ignore ignore t; t) ;; let subo ?pos ?len t = debug "Blit.subo" [t] (`pos pos, `len len) (<:sexp_of< [`pos of int option] * [`len of int option] >>) (<:sexp_of< (_, _) t >>) (fun () -> let t = subo ?pos ?len t in if !check_invariant then invariant ignore ignore t; t) ;; end module Blit_consume = struct open Blit_consume let unsafe_blit ~src ~dst ~dst_pos ~len = debug_blit "Blit_consume.unsafe_blit" ~src ~dst (`dst_pos dst_pos, `len len) (<:sexp_of< [`dst_pos of int] * [`len of int] >>) (<:sexp_of< unit >>) (fun () -> unsafe_blit ~src ~dst ~dst_pos ~len) ;; let blit ~src ~dst ~dst_pos ~len = debug_blit "Blit_consume.blit" ~src ~dst (`dst_pos dst_pos, `len len) (<:sexp_of< [`dst_pos of int] * [`len of int] >>) (<:sexp_of< unit >>) (fun () -> blit ~src ~dst ~dst_pos ~len) ;; let blito ~src ?src_len ~dst ?dst_pos () = debug_blit "Blit_consume.blito" ~src ~dst (`src_len src_len, `dst_pos dst_pos) (<:sexp_of< [`src_len of int option] * [`dst_pos of int option] >>) (<:sexp_of< unit >>) (fun () -> blito ~src ?src_len ~dst ?dst_pos ()) ;; let sub t ~len = debug "Blit_consume.sub" [t] (`len len) (<:sexp_of< [`len of int] >>) (<:sexp_of< (_, _) t >>) (fun () -> let t = sub t ~len in if !check_invariant then invariant ignore ignore t; t) ;; let subo ?len t = debug "Blit_consume.subo" [t] (`len len) (<:sexp_of< [`len of int option] >>) (<:sexp_of< (_, _) t >>) (fun () -> let t = subo ?len t in if !check_invariant then invariant ignore ignore t; t) ;; end module Blit_fill = struct open Blit_fill let unsafe_blit ~src ~src_pos ~dst ~len = debug_blit "Blit_fill.unsafe_blit" ~src ~dst (`src_pos src_pos, `len len) (<:sexp_of< [`src_pos of int] * [`len of int] >>) (<:sexp_of< unit >>) (fun () -> unsafe_blit ~src ~src_pos ~dst ~len) ;; let blit ~src ~src_pos ~dst ~len = debug_blit "Blit_fill.blit" ~src ~dst (`src_pos src_pos, `len len) (<:sexp_of< [`src_pos of int] * [`len of int] >>) (<:sexp_of< unit >>) (fun () -> blit ~src ~src_pos ~dst ~len) ;; let blito ~src ?src_pos ?src_len ~dst () = debug_blit "Blit_fill.blito" ~src ~dst (`src_pos src_pos, `src_len src_len) (<:sexp_of< [`src_pos of int option] * [`src_len of int option] >>) (<:sexp_of< unit >>) (fun () -> blito ~src ?src_pos ?src_len ~dst ()) ;; end module Blit_consume_and_fill = struct open Blit_consume_and_fill let unsafe_blit ~src ~dst ~len = debug_blit "Blit_consume_and_fill.unsafe_blit" ~src ~dst (`len len) (<:sexp_of< [`len of int] >>) (<:sexp_of< unit >>) (fun () -> unsafe_blit ~src ~dst ~len) ;; let blit ~src ~dst ~len = debug_blit "Blit_consume_and_fill.blit" ~src ~dst (`len len) (<:sexp_of< [`len of int] >>) (<:sexp_of< unit >>) (fun () -> blit ~src ~dst ~len) ;; let blito ~src ?src_len ~dst () = debug_blit "Blit_consume_and_fill.blito" ~src ~dst (`src_len src_len) (<:sexp_of< [`src_len of int option] >>) (<:sexp_of< unit >>) (fun () -> blito ~src ?src_len ~dst ()) ;; end module Expert = struct let buf = Expert.buf let hi_max = Expert.hi_max let hi = Expert.hi let lo = Expert.lo let lo_min = Expert.lo_min end module File_descr = Unix.File_descr let read_assume_fd_is_nonblocking t fd = debug "read_assume_fd_is_nonblocking" [t] fd (<:sexp_of< File_descr.t >>) (<:sexp_of< Syscall_result.Unit.t >>) (fun () -> read_assume_fd_is_nonblocking t fd) ;; let pread_assume_fd_is_nonblocking t fd ~offset = debug "pread_assume_fd_is_nonblocking" [t] (fd, `offset offset) (<:sexp_of< File_descr.t * [ `offset of int ] >>) (<:sexp_of< unit >>) (fun () -> pread_assume_fd_is_nonblocking t fd ~offset) ;; let recvfrom_assume_fd_is_nonblocking t fd = debug "recvfrom_assume_fd_is_nonblocking" [t] fd (<:sexp_of< File_descr.t >>) (<:sexp_of< Unix.sockaddr >>) (fun () -> recvfrom_assume_fd_is_nonblocking t fd) ;; let recvmmsg_assume_fd_is_nonblocking = Or_error.map recvmmsg_assume_fd_is_nonblocking ~f:(fun recvmmsg fd ?count ?srcs ts -> debug "recvmmsg_assume_fd_is_nonblocking" (Array.to_list ts) (fd, `count count, `srcs srcs) (<:sexp_of< (File_descr.t * [ `count of int option ] * [ `srcs of Unix.sockaddr array option ]) >>) (<:sexp_of< Unix.Syscall_result.Int.t >>) (fun () -> recvmmsg fd ?count ?srcs ts)) ;; let recvmmsg_assume_fd_is_nonblocking_no_options = Or_error.map recvmmsg_assume_fd_is_nonblocking_no_options ~f:(fun recvmmsg fd ~count ts -> debug "recvmmsg_assume_fd_is_nonblocking_no_options" (Array.to_list ts) (fd, `count count) (<:sexp_of< (File_descr.t * [ `count of int ]) >>) (<:sexp_of< Unix.Syscall_result.Int.t >>) (fun () -> recvmmsg fd ~count ts)) ;; let send_nonblocking_no_sigpipe () = Or_error.map (send_nonblocking_no_sigpipe ()) ~f:(fun send -> fun t fd -> debug "send_nonblocking_no_sigpipe" [t] (fd, t) (<:sexp_of< File_descr.t * (_, _) t >>) (<:sexp_of< Syscall_result.Unit.t >>) (fun () -> send t fd) ) ;; let sendto_nonblocking_no_sigpipe () = Or_error.map (sendto_nonblocking_no_sigpipe ()) ~f:(fun sendto -> fun t fd addr -> debug "sendto_nonblocking_no_sigpipe" [t] (fd, addr) <:sexp_of< File_descr.t * Unix.sockaddr >> <:sexp_of< Syscall_result.Unit.t >> (fun () -> sendto t fd addr) ) let write_assume_fd_is_nonblocking t fd = debug "write_assume_fd_is_nonblocking" [t] (fd, t) (<:sexp_of< File_descr.t * (_, _) t >>) (<:sexp_of< unit >>) (fun () -> write_assume_fd_is_nonblocking t fd) ;; let pwrite_assume_fd_is_nonblocking t fd ~offset = debug "pwrite_assume_fd_is_nonblocking" [t] (fd, t, `offset offset) (<:sexp_of< File_descr.t * (_, _) t * [ `offset of int ] >>) (<:sexp_of< unit >>) (fun () -> pwrite_assume_fd_is_nonblocking t fd ~offset) ;; module Unsafe = struct open Unsafe (* Sorry, these are almost textual copies of the functions above. For test purposes, it might be possible to functorize some of this. *) module Consume = struct let d name f sexp_of_result t = debug ("Unsafe.Consume." ^ name) [t] t <:sexp_of< (_, _) t >> sexp_of_result (fun () -> f t) ;; open Consume include Consume_blit_debug.Make (struct include Consume let module_name = "Unsafe.Consume" end) type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char t = d "char" char sexp_of_char t let int8 t = d "int8" int8 sexp_of_int t let int16_be t = d "int16_be" int16_be sexp_of_int t let int16_le t = d "int16_le" int16_le sexp_of_int t let int32_be t = d "int32_be" int32_be sexp_of_int t let int32_le t = d "int32_le" int32_le sexp_of_int t let uint8 t = d "uint8" uint8 sexp_of_int t let uint16_be t = d "uint16_be" uint16_be sexp_of_int t let uint16_le t = d "uint16_le" uint16_le sexp_of_int t let uint32_be t = d "uint32_be" uint32_be sexp_of_int t let uint32_le t = d "uint32_le" uint32_le sexp_of_int t let int64_be t = d "int64_be" int64_be sexp_of_int t let int64_le t = d "int64_le" int64_le sexp_of_int t let int64_t_be t = d "int64_t_be" int64_t_be sexp_of_int64 t let int64_t_le t = d "int64_t_le" int64_t_le sexp_of_int64 t let int64_be_trunc t = d "int64_be_trunc" int64_be_trunc sexp_of_int t let int64_le_trunc t = d "int64_le_trunc" int64_le_trunc sexp_of_int t let tail_padded_fixed_string ~padding ~len t = debug "Unsafe.Consume.tail_padded_fixed_string" [t] (`padding padding, `len len) <:sexp_of< [ `padding of char ] * [ `len of int ] >> sexp_of_string (fun () -> tail_padded_fixed_string ~padding ~len t) let string ?str_pos ?len t = debug "Unsafe.Consume.string" [t] (`str_pos str_pos, `len len) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] >> sexp_of_string (fun () -> string ?str_pos ?len t) let bigstring ?str_pos ?len t = debug "Unsafe.Consume.bigstring" [t] (`str_pos str_pos, `len len) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] >> sexp_of_bigstring (fun () -> bigstring ?str_pos ?len t) let bin_prot reader t = debug "Unsafe.Consume.bin_prot" [t] () <:sexp_of< unit >> <:sexp_of< _ >> (fun () -> bin_prot reader t) end module Fill = struct let d name f sexp_of_arg t arg = debug ("Unsafe.Fill." ^ name) [t] arg sexp_of_arg sexp_of_unit (fun () -> f t arg) ;; open Fill type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char t = d "char" char sexp_of_char t let int8 t = d "int8" int8 sexp_of_int t let int16_be t = d "int16_be" int16_be sexp_of_int t let int16_le t = d "int16_le" int16_le sexp_of_int t let int32_be t = d "int32_be" int32_be sexp_of_int t let int32_le t = d "int32_le" int32_le sexp_of_int t let uint8 t = d "uint8" uint8 sexp_of_int t let uint16_be t = d "uint16_be" uint16_be sexp_of_int t let uint16_le t = d "uint16_le" uint16_le sexp_of_int t let uint32_be t = d "uint32_be" uint32_be sexp_of_int t let uint32_le t = d "uint32_le" uint32_le sexp_of_int t let int64_be t = d "int64_be" int64_be sexp_of_int t let int64_le t = d "int64_le" int64_le sexp_of_int t let int64_t_be t = d "int64_t_be" int64_t_be sexp_of_int64 t let int64_t_le t = d "int64_t_le" int64_t_le sexp_of_int64 t let int64_be_trunc t = d "int64_be_trunc" int64_be_trunc sexp_of_int t let int64_le_trunc t = d "int64_le_trunc" int64_le_trunc sexp_of_int t let decimal t = d "decimal" decimal sexp_of_int t let tail_padded_fixed_string ~padding ~len t str = debug "Unsafe.Fill.tail_padded_fixed_string" [t] (`padding padding, `len len, str) <:sexp_of< [ `padding of char ] * [ `len of int ] * string >> sexp_of_unit (fun () -> tail_padded_fixed_string ~padding ~len t str) let string ?str_pos ?len t str = debug "Unsafe.Fill.string" [t] (`str_pos str_pos, `len len, str) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * string >> sexp_of_unit (fun () -> string ?str_pos ?len t str) let bigstring ?str_pos ?len t str = debug "Unsafe.Fill.bigstring" [t] (`str_pos str_pos, `len len, str) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * bigstring >> sexp_of_unit (fun () -> bigstring ?str_pos ?len t str) let bin_prot writer t a = debug "Unsafe.Fill.bin_prot" [t] () <:sexp_of< _ >> <:sexp_of< unit >> (fun () -> bin_prot writer t a) end module Peek = struct let d name f sexp_of_result t ~pos = debug ("Unsafe.Peek." ^ name) [t] (`pos pos) <:sexp_of< [ `pos of int ] >> sexp_of_result (fun () -> f t ~pos) ;; open Peek include Peek_blit_debug.Make (struct include Peek let module_name = "Unsafe.Peek" end) type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char t = d "char" char sexp_of_char t let int8 t = d "int8" int8 sexp_of_int t let int16_be t = d "int16_be" int16_be sexp_of_int t let int16_le t = d "int16_le" int16_le sexp_of_int t let int32_be t = d "int32_be" int32_be sexp_of_int t let int32_le t = d "int32_le" int32_le sexp_of_int t let uint8 t = d "uint8" uint8 sexp_of_int t let uint16_be t = d "uint16_be" uint16_be sexp_of_int t let uint16_le t = d "uint16_le" uint16_le sexp_of_int t let uint32_be t = d "uint32_be" uint32_be sexp_of_int t let uint32_le t = d "uint32_le" uint32_le sexp_of_int t let int64_be t = d "int64_be" int64_be sexp_of_int t let int64_le t = d "int64_le" int64_le sexp_of_int t let int64_t_be t = d "int64_t_be" int64_t_be sexp_of_int64 t let int64_t_le t = d "int64_t_le" int64_t_le sexp_of_int64 t let int64_be_trunc t = d "int64_be_trunc" int64_be_trunc sexp_of_int t let int64_le_trunc t = d "int64_le_trunc" int64_le_trunc sexp_of_int t let tail_padded_fixed_string ~padding ~len t ~pos = debug "Unsafe.Peek.tail_padded_fixed_string" [t] (`padding padding, `len len, `pos pos) <:sexp_of< [ `padding of char ] * [ `len of int ] * [ `pos of int ] >> sexp_of_string (fun () -> tail_padded_fixed_string ~padding ~len t ~pos) let string ?str_pos ?len t ~pos = debug "Unsafe.Peek.string" [t] (`str_pos str_pos, `len len, `pos pos) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * [ `pos of int ] >> sexp_of_string (fun () -> string ?str_pos ?len t ~pos) let bigstring ?str_pos ?len t ~pos = debug "Unsafe.Peek.bigstring" [t] (`str_pos str_pos, `len len, `pos pos) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * [ `pos of int ] >> sexp_of_bigstring (fun () -> bigstring ?str_pos ?len t ~pos) let bin_prot reader t ~pos = debug "Unsafe.Consume.bin_prot" [t] (`pos pos) <:sexp_of< [ `pos of int ] >> <:sexp_of< _ >> (fun () -> bin_prot reader t ~pos) end module Poke = struct let d name f sexp_of_arg t ~pos arg = debug ("Unsafe.Poke." ^ name) [t] (`pos pos, arg) (Tuple.T2.sexp_of_t <:sexp_of< [ `pos of int ] >> sexp_of_arg) sexp_of_unit (fun () -> f t ~pos arg) ;; open Poke type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char t = d "char" char sexp_of_char t let int8 t = d "int8" int8 sexp_of_int t let int16_be t = d "int16_be" int16_be sexp_of_int t let int16_le t = d "int16_le" int16_le sexp_of_int t let int32_be t = d "int32_be" int32_be sexp_of_int t let int32_le t = d "int32_le" int32_le sexp_of_int t let uint8 t = d "uint8" uint8 sexp_of_int t let uint16_be t = d "uint16_be" uint16_be sexp_of_int t let uint16_le t = d "uint16_le" uint16_le sexp_of_int t let uint32_be t = d "uint32_be" uint32_be sexp_of_int t let uint32_le t = d "uint32_le" uint32_le sexp_of_int t let int64_be t = d "int64_be" int64_be sexp_of_int t let int64_le t = d "int64_le" int64_le sexp_of_int t let int64_t_be t = d "int64_t_be" int64_t_be sexp_of_int64 t let int64_t_le t = d "int64_t_le" int64_t_le sexp_of_int64 t let int64_be_trunc t = d "int64_be_trunc" int64_be_trunc sexp_of_int t let int64_le_trunc t = d "int64_le_trunc" int64_le_trunc sexp_of_int t let decimal t ~pos arg = debug "Unsafe.Poke.decimal" [t] (`pos pos, arg) <:sexp_of< [ `pos of int ] * int >> sexp_of_int (fun () -> decimal t ~pos arg) let tail_padded_fixed_string ~padding ~len t ~pos str = debug "Unsafe.Poke.tail_padded_fixed_string" [t] (`padding padding, `len len, `pos pos, str) <:sexp_of< [ `padding of char ] * [ `len of int ] * [ `pos of int ] * string >> sexp_of_unit (fun () -> tail_padded_fixed_string ~padding ~len t ~pos str) let string ?str_pos ?len t ~pos str = debug "Unsafe.Poke.string" [t] (`str_pos str_pos, `len len, `pos pos, str) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * [ `pos of int ] * string >> sexp_of_unit (fun () -> string ?str_pos ?len t ~pos str) let bigstring ?str_pos ?len t ~pos str = debug "Unsafe.Poke.bigstring" [t] (`str_pos str_pos, `len len, `pos pos, str) <:sexp_of< [ `str_pos of int option ] * [ `len of int option ] * [ `pos of int ] * bigstring >> sexp_of_unit (fun () -> bigstring ?str_pos ?len t ~pos str) let bin_prot writer t ~pos a = debug "Unsafe.Poke.bin_prot" [t] (`pos pos) <:sexp_of< [ `pos of int ] >> <:sexp_of< unit >> (fun () -> bin_prot writer t a ~pos) end end end core-113.00.00/src/iobuf_debug.mli000066400000000000000000000013171256461075500165250ustar00rootroot00000000000000open Core_kernel.Std (* [Make] builds a module that is like [Iobuf], except that the module also has some controls for whether the various Iobuf functions do invariant checking and/or show debug messages. Initially, the [bool ref]'s are [true]. The performance of the functions in the module resulting from [Make] can be much worse than that of a plain [Iobuf], even with all the controls set to [false]. *) module Make () : sig (** We use [module type of struct include Iobuf end] rather than [module type of Iobuf] so that the debugging functions work on normal Iobufs. *) include module type of struct include Iobuf end val check_invariant : bool ref val show_messages : bool ref end core-113.00.00/src/iobuf_intf.ml000066400000000000000000000067371256461075500162410ustar00rootroot00000000000000open Core_kernel.Std (** [no_seek] and [seek] are phantom types used in a similar manner to [read] and [read_write]. *) type no_seek with sexp_of (** like [read] *) type seek = private no_seek with sexp_of (** like [read_write] *) (** A collection of iobuf access functions. This abstracts over [Iobuf.Consume], [Iobuf.Fill], [Iobuf.Peek], and [Iobuf.Poke]. *) module type Accessors = sig (** [('d, 'w) Iobuf.t] accessor function manipulating ['a], either writing it to the iobuf or reading it from the iobuf. *) type ('a, 'd, 'w) t constraint 'd = [> read ] type 'a bin_prot val char : (char , 'd, 'w) t val int8 : (int , 'd, 'w) t val int16_be : (int , 'd, 'w) t val int16_le : (int , 'd, 'w) t val int32_be : (int , 'd, 'w) t val int32_le : (int , 'd, 'w) t val uint8 : (int , 'd, 'w) t val uint16_be : (int , 'd, 'w) t val uint16_le : (int , 'd, 'w) t val uint32_be : (int , 'd, 'w) t val uint32_le : (int , 'd, 'w) t val int64_be : (int , 'd, 'w) t val int64_le : (int , 'd, 'w) t val int64_t_be : (Int64 .t, 'd, 'w) t val int64_t_le : (Int64 .t, 'd, 'w) t val tail_padded_fixed_string : padding:char -> len:int -> ( string , 'd, 'w) t val string : ?str_pos:int -> ?len:int -> ( string , 'd, 'w) t val bigstring : ?str_pos:int -> ?len:int -> (Bigstring.t, 'd, 'w) t val bin_prot : 'a bin_prot -> ('a , 'd, 'w) t val int64_be_trunc : (int , 'd, 'w) t val int64_le_trunc : (int , 'd, 'w) t end (** An iobuf window bound, either upper or lower. You can't see its int value, but you can save and restore it. *) module type Bound = sig type ('d, 'w) iobuf type t = private int (* performance hack: avoid the write barrier *) with sexp_of val window : (_, _) iobuf -> t val limit : (_, _) iobuf -> t val restore : t -> (_, seek) iobuf -> unit end (* The [src_pos] argument of {!Core_kernel.Blit.blit} doesn't make sense here. *) type ('src, 'dst) consuming_blit = src : 'src -> dst : 'dst -> dst_pos : int -> len : int -> unit type ('src, 'dst) consuming_blito = src : 'src -> ?src_len : int (** default is [Iobuf.length src] *) -> dst : 'dst -> ?dst_pos : int (** default is [0] *) -> unit -> unit module type Consuming_blit = sig type src type dst val blito : (src, dst) consuming_blito val blit : (src, dst) consuming_blit val unsafe_blit : (src, dst) consuming_blit (** [subo] defaults to using [Iobuf.length src] *) val subo : ?len:int -> src -> dst val sub : src -> len:int -> dst end (* For use in iobuf.mli -- can't be added to Std_internal due to dependencies *) module Unix = Core_unix core-113.00.00/src/iobuf_stubs.c000066400000000000000000000034431256461075500162420ustar00rootroot00000000000000 #include "iobuf.h" #include "unix_utils.h" #include "socketaddr.h" #include "recvmmsg.h" #ifdef JSC_RECVMMSG CAMLprim value iobuf_recvmmsg_assume_fd_is_nonblocking_stub( value v_fd, value v_iobufs, value v_count, value v_srcs) { CAMLparam4(v_fd, v_iobufs, v_count, v_srcs); CAMLlocal4(v_iobuf, v_lo, v_sockaddrs, v_hi); unsigned i; int n_read; unsigned count; count = (unsigned) Long_val(v_count); /* See comment in bigstring_stubs.c about the following bounds check. */ if (Long_val(v_count) < 0 || (intnat) count != Long_val(v_count)) { caml_invalid_argument("iobuf_recvmmsg_assume_fd_is_nonblocking_stub: " "v_count exceeds unsigned int"); } else if (count > RECVMMSG_MAX_COUNT) { caml_invalid_argument("iobuf_recvmmsg_assume_fd_is_nonblocking_stub: " "v_count exceeds RECVMMSG_MAX_COUNT"); } else { struct mmsghdr hdrs[RECVMMSG_MAX_COUNT]; struct iovec iovecs[RECVMMSG_MAX_COUNT]; for (i = 0; i < count; i++) { v_iobuf = Field(v_iobufs, i); v_lo = Field(v_iobuf, iobuf_lo); v_hi = Field(v_iobuf, iobuf_hi); iovecs[i].iov_base = get_bstr(Field(v_iobuf, iobuf_buf), v_lo); iovecs[i].iov_len = Long_val(v_hi) - Long_val(v_lo); } n_read = recvmmsg_assume_fd_is_nonblocking(v_fd, iovecs, count, v_srcs, hdrs); for (i = 0; (int) i < n_read; i++) { v_iobuf = Field(v_iobufs, i); v_lo = Field(v_iobuf, iobuf_lo); /* Knowing the structure of an Iobuf record (which we already * are dependent on), we can use Field(v_iobuf, iobuf_lo) as an * lvalue and skip the caml_modify done by Store_field. */ Field(v_iobuf, iobuf_lo) = Val_long(Long_val(v_lo) + hdrs[i].msg_len); } } CAMLreturn(Val_int(n_read)); } #endif /* JSC_RECVMMSG */ core-113.00.00/src/iobuf_tests.ml000066400000000000000000001647431256461075500164450ustar00rootroot00000000000000INCLUDE "core_config.mlh" open Core_kernel.Std_kernel open Iobuf_intf module Unix = Core_unix let is_error = Result.is_error let is_ok = Result.is_ok let ok_exn = Or_error.ok_exn let try_with = Or_error.try_with let log string a sexp_of_a = Printf.eprintf "%s\n%!" (Sexp.to_string_hum (<:sexp_of< string * a >> (string, a))); ;; module type Iobuf = module type of Iobuf module Test (Iobuf : sig include Iobuf val show_messages : bool ref end) : sig end = (struct let show_messages = Iobuf.show_messages let () = show_messages := false open Iobuf type nonrec ('d, 'w) t = ('d, 'w) t with sexp_of type nonrec seek = seek with sexp_of type nonrec no_seek = no_seek with sexp_of module type Bound = Bound let read_only = read_only let no_seek = no_seek let strings = [ ""; "a"; "hello"; "\000"; "\000\000\000"; "\000hello"; String.make 1000 'x' ] IFDEF ARCH_SIXTYFOUR THEN (* [large_int] creates an int that is not representable on 32-bit systems. *) let large_int a b c d = (a lsl 48) lor (b lsl 32) lor (c lsl 16) lor d ENDIF type iter_examples_state = { string : string ; len : int ; capacity : int ; pos : int } with sexp let iter_examples ~f = List.iter strings ~f:(fun string -> let len = String.length string in for capacity = max 1 len to len + 2 do for pos = 0 to 2 do if pos + len <= capacity then try f (create ~len:capacity) string ~pos with | e -> failwiths "iter_examples" ({ string; len; capacity; pos }, e) <:sexp_of< iter_examples_state * exn >> done done ) ;; type iter_slices_state = { pos : int option ; len : int option ; pos' : int ; len' : int ; is_valid : bool } with sexp let iter_slices n ~f = let choices = [ None ; Some (-1) ; Some 0 ; Some 1 ; Some (n / 3) ; Some (n - 1) ; Some n ; Some (n + 1) ] in List.iter choices ~f:(fun pos -> List.iter choices ~f:(fun len -> let pos' = Option.value pos ~default:0 in let len' = Option.value len ~default:(n - pos') in let is_valid = pos' >= 0 && pos' <= n && len' >= 0 && len' <= n - pos' in if !show_messages && false then log "iter_slice" { pos; len; pos'; len'; is_valid } <:sexp_of< iter_slices_state >>; try f ?pos ?len ~pos' ~len' ~is_valid () with e -> failwiths "iter_slices" ( { pos; len; pos'; len'; is_valid } , e , String.split ~on:'\n' (Exn.backtrace ()) ) <:sexp_of< iter_slices_state * exn * string list >>)) ;; let invariant = invariant TEST_UNIT = invariant ignore ignore (create ~len:(Random.int 100_000 + 1)); ;; let create = create let capacity = capacity let length = length let is_empty = is_empty (* [create] with random capacity. *) TEST_MODULE = struct let n = Random.int 100_000 + 1 in assert (n > 0); let t = create ~len:n in assert (capacity t = n); assert (length t = n); assert (not (is_empty t)); end (* [create] with user-supplied capacity. *) TEST_UNIT = let t = create ~len:1 in assert (capacity t = 1); assert (length t = 1); assert (not (is_empty t)); ;; TEST = is_empty (create ~len:0) (* [create] with invalid capacity. *) TEST_UNIT = assert (is_error (try_with (fun () -> ignore (create ~len:(-1) : (_, _) t)))) ;; let crc32 = crc32 TEST_MODULE = struct let str = "The quick brown fox jumps over the lazy dog" let len = String.length str let crc = Int63.of_int64_exn 0x414fa339L TEST_UNIT = <:test_result< Int63.Hex.t >> (crc32 (of_string str)) ~expect:crc TEST_UNIT = let t = of_string ("12345" ^ str ^ "12345") in advance t 5; resize t ~len; <:test_result< Int63.Hex.t >> (crc32 t) ~expect:crc end ;; module Accessors (Accessors : sig include module type of Unsafe val is_safe : bool end) = struct open Accessors (* [window] *) TEST_UNIT = let t = create ~len:10 in let n = length t in assert (n = 10); Poke.char t ~pos:0 'a'; Poke.char t ~pos:1 'b'; sub_shared t |> (fun t -> assert (length t = n); assert (Consume.char t = 'a')); assert (Consume.char t = 'a'); assert (Consume.char t = 'b'); ;; let in_each_window t ~f = let n = length t in for pos = 0 to n do for len = 0 to n - pos do sub_shared t ~pos ~len |> f; done; done; ;; (* [sub_shared ?pos ?len] *) TEST_UNIT = let test t = let n = length t in let window_length ?pos ?len () = sub_shared t ?pos ?len |> length in let window_fails ?pos ?len () = is_error (try_with (fun () -> ignore (sub_shared t ?pos ?len |> ignore))) in assert (window_fails ~pos:(-1) ()); assert (window_fails ~pos:(n + 1) ()); assert (window_fails ~len:(-1) ()); assert (window_fails ~len:(n + 1) ()); assert (window_length () = n); for len = 0 to n do assert (window_length ~len () = len); done; for pos = 0 to n do assert (window_length ~pos () = n - pos); for len = 0 to n - pos do assert (window_length ~pos ~len () = len); done; done; in for len = 1 to 5 do let t = create ~len in test t; in_each_window t ~f:test; done; ;; module Lo_bound = struct type t = Lo_bound.t let sexp_of_t = Lo_bound.sexp_of_t let window, restore = Lo_bound.(window, restore) TEST = let iobuf = create ~len:2 in let snapshot = window iobuf in assert (length iobuf = 2); advance iobuf 1; assert (length iobuf = 1); restore snapshot iobuf; assert (length iobuf = 2); (* the same snapshot can be reused *) advance iobuf 1; assert (length iobuf = 1); restore snapshot iobuf; assert (length iobuf = 2); (* but can fail in combination with narrow *) advance iobuf 1; narrow iobuf; assert (capacity iobuf = 1); assert (length iobuf = 1); is_error (try_with (fun () -> restore snapshot iobuf)) let limit = Lo_bound.limit TEST = let buf = of_string "123abcDEF" in advance buf 3; let lo_min = limit buf in resize buf ~len:3; restore lo_min buf; String.equal "123abc" (to_string buf) end module Hi_bound = struct type t = Hi_bound.t let sexp_of_t = Hi_bound.sexp_of_t let window, restore = Hi_bound.(window, restore) TEST = let iobuf = create ~len:2 in let snapshot = window iobuf in assert (length iobuf = 2); resize iobuf ~len:1; assert (length iobuf = 1); restore snapshot iobuf; assert (length iobuf = 2); (* the same snapshot can be reused *) resize iobuf ~len:1; assert (length iobuf = 1); restore snapshot iobuf; assert (length iobuf = 2); (* but can fail in combination with narrow *) resize iobuf ~len:1; narrow iobuf; assert (capacity iobuf = 1); assert (length iobuf = 1); is_error (try_with (fun () -> restore snapshot iobuf)) let limit = Hi_bound.limit TEST = let buf = of_string "123abcDEF" in resize buf ~len:3; let hi_max = limit buf in advance buf 3; restore hi_max buf; String.equal "abcDEF" (to_string buf) end let rewind = rewind let reset = reset let flip_lo = flip_lo let bounded_flip_lo = bounded_flip_lo TEST = let buf = of_string "123abcDEF" in Iobuf.advance buf 3; let lo = Lo_bound.window buf in Iobuf.advance buf 3; bounded_flip_lo buf lo; String.equal "abc" (Iobuf.to_string buf) ;; let flip_hi = flip_hi TEST = let buf = of_string "123abcDEF" in Iobuf.resize buf ~len:3; Iobuf.flip_hi buf; String.equal "abcDEF" (Iobuf.to_string buf) ;; TEST = let buf = of_string "123abcDEF" in Iobuf.resize buf ~len:6; Iobuf.narrow buf; Iobuf.resize buf ~len:3; Iobuf.flip_hi buf; String.equal "abc" (Iobuf.to_string buf) ;; let bounded_flip_hi = bounded_flip_hi TEST = let buf = of_string "123abcDEF" in let hi = Hi_bound.window buf in Iobuf.advance buf 3; Iobuf.resize buf ~len:3; bounded_flip_hi buf hi; String.equal "DEF" (Iobuf.to_string buf) ;; let compact = compact let sub_shared = sub_shared let set_bounds_and_buffer_sub = set_bounds_and_buffer_sub let set_bounds_and_buffer = set_bounds_and_buffer let narrow = narrow let narrow_lo = narrow_lo let narrow_hi = narrow_hi TEST = let buf = of_string "123" in assert (capacity buf = 3); assert (length buf = 3); advance buf 1; assert (capacity buf = 3); assert (length buf = 2); resize buf ~len:1; assert (capacity buf = 3); assert (length buf = 1); narrow buf; assert (capacity buf = 1); assert (length buf = 1); advance buf 1; assert (capacity buf = 1); assert (length buf = 0); reset buf; assert (capacity buf = 1); length buf = 1 ;; TEST = let src = of_string "123abcDEF" in let dst = Iobuf.create ~len:0 in set_bounds_and_buffer ~src ~dst; src = dst ;; TEST = let src = of_string "123abcDEF" in let dst = Iobuf.create ~len:0 in set_bounds_and_buffer_sub ~src ~dst (); src = dst ;; TEST = let src = of_string "123abcDEF" in let src = Iobuf.sub_shared ~pos:1 ~len:5 src in let dst = Iobuf.create ~len:0 in set_bounds_and_buffer ~src ~dst; src = dst ;; TEST = let src = of_string "123abcDEF" in let src = Iobuf.sub_shared ~pos:1 ~len:5 src in let dst = Iobuf.create ~len:0 in set_bounds_and_buffer_sub ~src ~dst (); src = dst ;; TEST = let src = of_string "123abcDEF" in let src_sub = Iobuf.sub_shared ~pos:1 ~len:5 src in let dst = Iobuf.create ~len:0 in set_bounds_and_buffer_sub ~pos:2 ~len:2 ~src:src_sub ~dst (); let src_sub' = Iobuf.sub_shared ~pos:3 ~len:2 src in src_sub' = dst ;; TEST = let buf1 = of_string "123abcDEF" in let buf2 = of_string "123abcDEF" in Iobuf.set_bounds_and_buffer ~src:buf1 ~dst:buf1; buf1 = buf2 ;; let bounded_compact = bounded_compact TEST = let buf = of_string "123abcDEFghiJKL" in advance buf 3; let lo = Lo_bound.window buf in Iobuf.resize buf ~len:9; let hi = Hi_bound.window buf in advance buf 6; bounded_compact buf lo hi; assert (String.equal "DEFghi" (Iobuf.to_string buf)); Iobuf.reset buf; String.equal "123ghiDEFghiJKL" (Iobuf.to_string buf) ;; let resize = resize let unsafe_resize = unsafe_resize TEST_UNIT = List.iter [ resize,true ; unsafe_resize,false ] ~f:(fun (resize, test_invalid_access) -> let buf = of_string "123abcDEF" in if test_invalid_access then begin let resize_fails amount = is_error (try_with (fun () -> resize buf ~len:amount)) in assert (resize_fails (-1)); assert (resize_fails (Iobuf.length buf + 1)) end; let sub = ref "" in let f (buf : (read, seek) t) = advance buf 3; resize buf ~len:3; sub := to_string buf; in Iobuf.protect_window_and_bounds buf ~f; assert (String.equal (to_string buf) "123abcDEF" && String.equal !sub "abc")); ;; TEST = let buf = of_string "123abcDEF" in let sub = ref "" in let f (buf : (read, seek) t) = advance buf 3; resize buf ~len:3; sub := to_string buf; raise Not_found; in try Iobuf.protect_window_and_bounds buf ~f; false with | Not_found -> String.equal (to_string buf) "123abcDEF" && String.equal !sub "abc"; ;; let protect_window_and_bounds = protect_window_and_bounds TEST_UNIT = let test t = let n = length t in rewind t; assert (length t = n); advance t 1; assert (length t = n - 1); rewind t; assert (length t = n); advance t 1; assert (length t = n - 1); rewind t; assert (length t = n); rewind t; in test (create ~len:10); let t = create ~len:10 in sub_shared t ~pos:1 |> test; ;; let to_string = to_string let of_string = of_string TEST_UNIT = List.iter strings ~f:(fun string -> assert (String.equal string (to_string (of_string string)))) ;; let to_string_hum = to_string_hum TEST_UNIT = <:test_eq< string >> (to_string_hum (Iobuf.of_string (String.init 256 ~f:Char.of_int_exn ^ "foo"))) "Iobuf: bigstring length 259; limits [0,259]; window [0,259]; contents within limits:\ \n0x0000: 00 01 02 03 04 05 06 07 ........ ........ 08 09 0a 0b 0c 0d 0e 0f\ \n0x0010: 10 11 12 13 14 15 16 17 ........ ........ 18 19 1a 1b 1c 1d 1e 1f\ \n0x0020: 20 21 22 23 24 25 26 27 !\"#$%&' ()*+,-./ 28 29 2a 2b 2c 2d 2e 2f\ \n0x0030: 30 31 32 33 34 35 36 37 01234567 89:;<=>? 38 39 3a 3b 3c 3d 3e 3f\ \n0x0040: 40 41 42 43 44 45 46 47 @ABCDEFG HIJKLMNO 48 49 4a 4b 4c 4d 4e 4f\ \n0x0050: 50 51 52 53 54 55 56 57 PQRSTUVW XYZ[\\]^_ 58 59 5a 5b 5c 5d 5e 5f\ \n0x0060: 60 61 62 63 64 65 66 67 `abcdefg hijklmno 68 69 6a 6b 6c 6d 6e 6f\ \n0x0070: 70 71 72 73 74 75 76 77 pqrstuvw xyz{|}~. 78 79 7a 7b 7c 7d 7e 7f\ \n0x0080: 80 81 82 83 84 85 86 87 ........ ........ 88 89 8a 8b 8c 8d 8e 8f\ \n0x0090: 90 91 92 93 94 95 96 97 ........ ........ 98 99 9a 9b 9c 9d 9e 9f\ \n0x00a0: a0 a1 a2 a3 a4 a5 a6 a7 ........ ........ a8 a9 aa ab ac ad ae af\ \n0x00b0: b0 b1 b2 b3 b4 b5 b6 b7 ........ ........ b8 b9 ba bb bc bd be bf\ \n0x00c0: c0 c1 c2 c3 c4 c5 c6 c7 ........ ........ c8 c9 ca cb cc cd ce cf\ \n0x00d0: d0 d1 d2 d3 d4 d5 d6 d7 ........ ........ d8 d9 da db dc dd de df\ \n0x00e0: e0 e1 e2 e3 e4 e5 e6 e7 ........ ........ e8 e9 ea eb ec ed ee ef\ \n0x00f0: f0 f1 f2 f3 f4 f5 f6 f7 ........ ........ f8 f9 fa fb fc fd fe ff\ \n0x0100: 66 6f 6f foo " ;; TEST_UNIT = List.iter strings ~f:(fun str1 -> List.iter strings ~f:(fun str2 -> let hum1 = to_string_hum (of_string str1) in let hum2 = to_string_hum (of_string str2) in <:test_eq< bool >> (String.equal str1 str2) (String.equal hum1 hum2))) let of_bigstring = of_bigstring TEST_UNIT = List.iter strings ~f:(fun string -> let bigstring = Bigstring.of_string string in iter_slices (String.length string) ~f:(fun ?pos ?len ~pos':_ ~len':_ ~is_valid () -> match try_with (fun () -> of_bigstring bigstring ?pos ?len) with | Error _ -> assert (not is_valid) | Ok t -> assert is_valid; assert (String.equal (to_string t) (Bigstring.to_string bigstring ?pos ?len)))); ;; let advance = advance let unsafe_advance = unsafe_advance TEST_UNIT = List.iter [advance, true; unsafe_advance, false] ~f:(fun (advance, test_invalid_access) -> for len = 1 to 5 do let t = create ~len in let advance_fails amount = is_error (try_with (fun () -> advance t amount)) in if test_invalid_access then begin assert (advance_fails (-1)); assert (advance_fails (len + 1)); end; for amount = 0 to len do sub_shared t |> (fun t -> advance t amount; assert (length t = len - amount)) done; done; ) ;; let consume_bin_prot = consume_bin_prot let fill_bin_prot = fill_bin_prot TEST_UNIT = let t = create ~len:2000 in List.iter strings ~f:(fun s -> assert (is_ok (fill_bin_prot t String.bin_writer_t s)); flip_lo t; let s' = ok_exn (consume_bin_prot t String.bin_reader_t) in reset t; assert (String.equal s s')); ;; module Intf (Intf : sig include Accessors val t_pos_1 : (read_write, seek) Iobuf.t -> int -> ('a, read_write, seek) t -> 'a -> string (* corresponding buffer contents *) -> ('a -> Sexp.t) -> unit val bin_prot_char : (char, 'd, 'w) t end) = struct open Intf type nonrec ('a, 'd, 'w) t = ('a, 'd, 'w) t let char = char let int8 = int8 let uint8 = uint8 let int16_be = int16_be let int16_le = int16_le let uint16_be = uint16_be let uint16_le = uint16_le let int32_be = int32_be let int32_le = int32_le let uint32_be = uint32_be let uint32_le = uint32_le let int64_be = int64_be let int64_le = int64_le let int64_t_be = int64_t_be let int64_t_le = int64_t_le let int64_be_trunc = int64_be_trunc let int64_le_trunc = int64_le_trunc let tail_padded_fixed_string = tail_padded_fixed_string let string = string let bigstring = bigstring let bin_prot = bin_prot TEST_UNIT = let buf = of_string "ABCDEFGHIJ" in t_pos_1 buf 1 int8 127 "A\127CDEFGHIJ" sexp_of_int; t_pos_1 buf 1 int8 (-1) "A\255CDEFGHIJ" sexp_of_int; t_pos_1 buf 1 int8 (-128) "A\128CDEFGHIJ" sexp_of_int; t_pos_1 buf 1 uint8 0 "A\000CDEFGHIJ" sexp_of_int; t_pos_1 buf 1 uint8 255 "A\255CDEFGHIJ" sexp_of_int; t_pos_1 buf 1 char 'K' "AKCDEFGHIJ" sexp_of_char; t_pos_1 buf 1 char '\254' "A\254CDEFGHIJ" sexp_of_char; t_pos_1 buf 1 int8 (-1) "A\255CDEFGHIJ" sexp_of_int; t_pos_1 buf 1 uint8 12 "A\012CDEFGHIJ" sexp_of_int; t_pos_1 buf 1 bin_prot_char 'x' "AxCDEFGHIJ" sexp_of_char; t_pos_1 buf 2 int16_be 0x0102 "A\001\002DEFGHIJ" sexp_of_int; t_pos_1 buf 2 int16_le 0x0304 "A\004\003DEFGHIJ" sexp_of_int; t_pos_1 buf 2 int16_be (-2) "A\255\254DEFGHIJ" sexp_of_int; t_pos_1 buf 2 int16_le (-3) "A\253\255DEFGHIJ" sexp_of_int; t_pos_1 buf 2 uint16_be 0xFFFE "A\255\254DEFGHIJ" sexp_of_int; t_pos_1 buf 2 uint16_le 0xFDFC "A\252\253DEFGHIJ" sexp_of_int; t_pos_1 buf 2 int16_be 0x0506 "A\005\006DEFGHIJ" sexp_of_int; t_pos_1 buf 2 int16_le 0x0708 "A\008\007DEFGHIJ" sexp_of_int; t_pos_1 buf 3 (tail_padded_fixed_string ~padding:'p' ~len:3) "x" "AxppEFGHIJ" sexp_of_string; t_pos_1 buf 3 (string ?str_pos:None ~len:3) "123" "A123EFGHIJ" sexp_of_string; t_pos_1 buf 3 (bigstring ?str_pos:None ~len:3) (Bigstring.of_string "klm") "AklmEFGHIJ" sexp_of_bigstring; t_pos_1 buf 4 int32_be 0x0A0B0C0D "A\010\011\012\013FGHIJ" sexp_of_int; t_pos_1 buf 4 int32_le 0x01020304 "A\004\003\002\001FGHIJ" sexp_of_int; t_pos_1 buf 4 int32_be (-0x01020305) "A\254\253\252\251FGHIJ" sexp_of_int; t_pos_1 buf 4 int32_le (-0x05060709) "A\247\248\249\250FGHIJ" sexp_of_int; IFDEF ARCH_SIXTYFOUR THEN t_pos_1 buf 4 uint32_be (large_int 0 0 0xF6F5 0xF4F3) "A\246\245\244\243FGHIJ" sexp_of_int; t_pos_1 buf 4 uint32_le (large_int 0 0 0xFBFA 0xF9F8) "A\248\249\250\251FGHIJ" sexp_of_int; t_pos_1 buf 8 int64_be (large_int 0x0102 0x0304 0x0506 0x0708) "A\001\002\003\004\005\006\007\008J" sexp_of_int; t_pos_1 buf 8 int64_le (large_int 0x090a 0x0b0c 0x0d0e 0x0f10) "A\016\015\014\013\012\011\010\009J" sexp_of_int; t_pos_1 buf 8 int64_be (-(large_int 0x0102 0x0304 0x0506 0x0709)) "A\254\253\252\251\250\249\248\247J" sexp_of_int; t_pos_1 buf 8 int64_le (-(large_int 0x0102 0x0304 0x0506 0x0709)) "A\247\248\249\250\251\252\253\254J" sexp_of_int; t_pos_1 buf 8 int64_be_trunc (large_int 0x0102 0x0304 0x0506 0x0708) "A\001\002\003\004\005\006\007\008J" sexp_of_int; t_pos_1 buf 8 int64_le_trunc (large_int 0x090a 0x0b0c 0x0d0e 0x0f10) "A\016\015\014\013\012\011\010\009J" sexp_of_int; t_pos_1 buf 8 int64_be_trunc (-(large_int 0x0102 0x0304 0x0506 0x0709)) "A\254\253\252\251\250\249\248\247J" sexp_of_int; t_pos_1 buf 8 int64_le_trunc (-(large_int 0x0102 0x0304 0x0506 0x0709)) "A\247\248\249\250\251\252\253\254J" sexp_of_int ELSE () ENDIF; t_pos_1 buf 8 int64_t_be 1L "A\000\000\000\000\000\000\000\001J" sexp_of_int64; t_pos_1 buf 8 int64_t_le 1L "A\001\000\000\000\000\000\000\000J" sexp_of_int64; t_pos_1 buf 8 int64_t_be 0x8000000000000000L "A\128\000\000\000\000\000\000\000J" sexp_of_int64; t_pos_1 buf 8 int64_t_le 0x8000000000000000L "A\000\000\000\000\000\000\000\128J" sexp_of_int64 end let cases_for_testing_decimal = [ Int.min_value; (Int.min_value + 1); -100; -9; 0; 10; 15; 45; 120; 987; 2814; 10000; 100_000; 1_000_000; Int.max_value ] @ List.init 1_000 ~f:(fun _ -> Random.int (1 lsl 29) lsl Random.int 35) ;; module Poke = struct include Intf (struct include Poke type 'a bin_prot = 'a Bin_prot.Type_class.writer let t_pos_1 buf _ f arg str _sexp_of_arg = f buf ~pos:1 arg; <:test_eq< string >> str (to_string buf) let bin_prot_char t ~pos a = bin_prot Char.bin_writer_t t ~pos a (* Static permission tests for the cases that do compile. Since the functions all use essentially the same type definitions, we don't need to test all of them. We've already tested them on a (read_write, seek) Iobuf.t above. *) TEST_UNIT = char (of_string "a" : (_, no_seek) Iobuf.t) ~pos:0 'b' TEST_UNIT = char (of_string "a" : (_, seek) Iobuf.t) ~pos:0 'b' TEST_UNIT = char (of_string "a" : (read_write, _) Iobuf.t) ~pos:0 'b' end) let decimal = Poke.decimal TEST_UNIT "Poke.decimal" = let pos = 1 in let t = create ~len:(20 + pos) in List.iter cases_for_testing_decimal ~f:(fun x -> Iobuf.reset t; let len = decimal t ~pos x in <:test_eq> (Int.to_string x) (Iobuf.to_string (Iobuf.sub_shared ~pos t) ~len)) end TEST_UNIT = let t = create ~len:10 in let n = length t in assert (n = 10); Poke.char t ~pos:0 'a'; Poke.char t ~pos:1 'b'; sub_shared t |> (fun t -> assert (length t = n); assert (Consume.char t = 'a')); assert (Consume.char t = 'a'); assert (Consume.char t = 'b'); let ws = (t :> (read_write, seek) t) in let rs = (ws :> (read, seek) t) in ignore (rs :> (read, no_seek) t); ignore (ws :> (read_write, no_seek) t); ;; let test_peek_to (blito : (Peek.src, _) Core_kernel.Std_kernel.Blit.blito) create sub_string of_string to_string = iter_examples ~f:(fun t string ~pos -> let n = String.length string in iter_slices n ~f:(fun ?pos:str_pos ?len ~pos' ~len' ~is_valid () -> let fill_result = Or_error.try_with (fun () -> sub_shared t ~pos |> (fun t -> Fill.string t string ?str_pos ?len)) in <:test_eq< bool >> (is_ok fill_result) is_valid; let str = create n in let consume_result = Or_error.try_with (fun () -> sub_shared (read_only (no_seek t)) ~pos |> (fun t -> blito ~src:t ~src_pos:0 ~src_len:len' ~dst:str ?dst_pos:str_pos ())) in begin match consume_result, is_valid with | Error _, false -> () | Ok (), true -> <:test_eq< string >> (String.sub string ~pos:pos' ~len:len') (sub_string str ~pos:pos' ~len:len') | _, _ -> failwiths "test_peek_to" ( (consume_result, `is_valid is_valid) , String.split ~on:'\n' (Exn.backtrace ()) ) <:sexp_of< (unit Or_error.t * [ `is_valid of bool ]) * string list >> end ) ); let t = Iobuf.of_string "012345678" in let dst = of_string "abcdefhij" in blito ~src:t ~src_len:3 ~dst ~dst_pos:3 (); <:test_eq< string >> (Iobuf.to_string t) "012345678"; <:test_eq< string >> (to_string dst) "abc012hij" ;; let test_peek_to_string blito = test_peek_to blito String.create String.sub ident ident let test_peek_to_bigstring blito = test_peek_to blito Bigstring.create (fun s ~pos ~len -> Bigstring.to_string s ~pos ~len) Bigstring.of_string Bigstring.to_string ;; module Peek = struct include Intf (struct include Peek type 'a bin_prot = 'a Bin_prot.Type_class.reader let t_pos_1 _ _ f expected str sexp_of_res = let res = f (of_string str) ~pos:1 in if not (Pervasives.(=) res expected) then failwiths (sprintf "%S" str) (res, expected) (Tuple.T2.sexp_of_t sexp_of_res sexp_of_res) let bin_prot_char t ~pos = bin_prot Char.bin_reader_t t ~pos (* static permission tests; see above *) TEST = Char.(=) 'a' (char (of_string "a" : (_, no_seek) Iobuf.t) ~pos:0) TEST = Char.(=) 'a' (char (of_string "a" : (_, seek) Iobuf.t) ~pos:0) TEST = Char.(=) 'a' (char (of_string "a" : (read, _) Iobuf.t) ~pos:0) TEST = Char.(=) 'a' (char (of_string "a" : (read_write, _) Iobuf.t) ~pos:0) end) open Peek module To_string = struct open Peek.To_string let blito = blito TEST_UNIT = test_peek_to_string blito (* Mostly rely on the [Blit.Make_distinct] testing. *) let blit, unsafe_blit, sub, subo = blit, unsafe_blit, sub, subo end module To_bigstring = struct open Peek.To_bigstring let blito = blito TEST_UNIT = test_peek_to_bigstring blito (* Mostly rely on the [Blit.Make_distinct] testing. *) let blit, unsafe_blit, sub, subo = blit, unsafe_blit, sub, subo end type nonrec src = src end TEST_UNIT = let s = "hello" in let t = of_string s in for i = 0 to String.length s - 1 do assert (Char.equal (Peek.char t ~pos:i) (s.[i])); Poke.char t ~pos:i 'z'; assert (Char.equal (Peek.char t ~pos:i) 'z'); done; if is_safe then (assert (is_error (try_with (fun () -> Peek.char t ~pos:(-1)))); assert (is_error (try_with (fun () -> Poke.char t ~pos:(-1) 'z'))); assert (is_error (try_with (fun () -> Peek.char t ~pos:(String.length s)))); assert (is_error (try_with (fun () -> Poke.char t ~pos:(String.length s) 'z')))); ;; TEST_UNIT = List.iter [ 0; 1 ] ~f:(fun pos -> let t = create ~len:10 in IFDEF ARCH_SIXTYFOUR THEN let i = large_int 0x1234 0x5678 0x90AB 0xCDEF in Poke.int64_le t ~pos i; assert (Peek.int64_le t ~pos = i); Poke.int64_be t ~pos i; assert (Peek.int64_be t ~pos = i); ELSE () ENDIF; let i = 0x1234_5678 in Poke.int32_le t ~pos i; assert (Peek.int32_le t ~pos = i); Poke.int32_be t ~pos i; assert (Peek.int32_be t ~pos = i); let i = 0x1234 in Poke.int32_le t ~pos i; assert (Peek.int32_le t ~pos = i); Poke.int32_be t ~pos i; assert (Peek.int32_be t ~pos = i); ) ;; module Fill = struct include Intf (struct include Fill type 'a bin_prot = 'a Bin_prot.Type_class.writer let t_pos_1 buf n f arg str _sexp_of_arg = rewind buf; advance buf 1; f buf arg; assert (Iobuf.length buf = String.length str - 1 - n); rewind buf; <:test_eq< string >> str (to_string buf) let bin_prot_char t a = bin_prot Char.bin_writer_t t a TEST_UNIT = let t = of_string "abc" in bin_prot Char.bin_writer_t t 'd'; bin_prot Char.bin_writer_t t 'e'; <:test_eq< string >> "c" (to_string t); flip_lo t; assert (try bin_prot String.bin_writer_t t "fgh"; false with _ -> true); <:test_eq< string >> "de" (to_string t); reset t; <:test_eq< string >> "dec" (to_string t); bin_prot Char.bin_writer_t t 'i'; bin_prot Char.bin_writer_t t 'j'; bin_prot Char.bin_writer_t t 'k'; assert (is_empty t); flip_lo t; <:test_eq< string >> "ijk" (to_string t) (* static permission tests; see above *) TEST_UNIT = char (of_string "a" : (_, seek) Iobuf.t) 'b' TEST_UNIT = char (of_string "a" : (read_write, _) Iobuf.t) 'b' end) let decimal = Fill.decimal TEST_UNIT "Fill.decimal" = let t = create ~len:20 in List.iter cases_for_testing_decimal ~f:(fun x -> Iobuf.reset t; decimal t x; Iobuf.flip_lo t; <:test_eq> (Int.to_string x) (Iobuf.to_string t)) end TEST_UNIT = List.iter [ ""; "a"; "ab" ] ~f:(fun s -> let len = String.length s in for capacity = max 1 len to len + 2 do let t = create ~len:capacity in for pos = 0 to capacity - len do sub_shared t ~pos |> (fun t -> Fill.string t s); sub_shared t ~pos ~len |> (fun t -> let s' = to_string t in assert (String.equal s s'); assert (length t = len); (* [to_string] didn't change the length *) ); done; done) ;; TEST_UNIT = let src = create ~len:5 in let len = 3 in let str = "Hi." in assert (len >= String.length str); assert (capacity src >= len); Poke.string src str ~pos:0; Blit.blit ~src ~src_pos:0 ~dst:src ~dst_pos:2 ~len; <:test_result< string >> (to_string src) ~expect:"HiHi." ;; TEST_UNIT = let src = create ~len:5 in let len = 3 in let str = "Hi." in assert (len >= String.length str); assert (capacity src >= len); let dst = create ~len:5 in Fill.string src str; flip_lo src; Blit_consume_and_fill.blit ~src ~dst ~len; flip_lo dst; <:test_result< string >> (Consume.string dst) ~expect:str ;; let test_consume_to (blito : (Consume.src, _) consuming_blito) create sub_string of_string to_string = iter_examples ~f:(fun t string ~pos -> let n = String.length string in iter_slices n ~f:(fun ?pos:str_pos ?len ~pos' ~len' ~is_valid () -> let fill_result = Or_error.try_with (fun () -> sub_shared t ~pos |> (fun t -> Fill.string t string ?str_pos ?len)) in <:test_eq< bool >> (is_ok fill_result) is_valid; let str = create n in let consume_result = Or_error.try_with (fun () -> sub_shared (read_only t) ~pos |> (fun t -> blito ~src:t ~src_len:len' ~dst:str ?dst_pos:str_pos ())) in begin match consume_result, is_valid with | Error _, false -> () | Ok (), true -> <:test_eq< string >> (String.sub string ~pos:pos' ~len:len') (sub_string str ~pos:pos' ~len:len'); | _, _ -> failwiths "test_consume_to" (consume_result, is_valid, String.split ~on:'\n' (Exn.backtrace ())) <:sexp_of< unit Or_error.t * bool * string list >> end)); let t = Iobuf.of_string "012345678" in let dst = of_string "abcdefhij" in blito ~src:t ~src_len:3 ~dst ~dst_pos:3 (); <:test_eq< string >> (Iobuf.to_string t) "345678"; <:test_eq< string >> (to_string dst) "abc012hij" ;; let test_consume_to_string blito = test_consume_to blito String.create String.sub ident ident let test_consume_to_bigstring blito = test_consume_to blito Bigstring.create (fun s ~pos ~len -> Bigstring.to_string s ~pos ~len) Bigstring.of_string Bigstring.to_string ;; module Consume = struct include Intf (struct include Consume type 'a bin_prot = 'a Bin_prot.Type_class.reader let t_pos_1 _ n f expected str sexp_of_res = let buf = of_string str in advance buf 1; let res = f buf in assert (Iobuf.length buf = String.length str - 1 - n); rewind buf; if not (Pervasives.(=) res expected) then failwiths (sprintf "%S" (to_string buf)) (res, expected) (Tuple.T2.sexp_of_t sexp_of_res sexp_of_res) let bin_prot_char t = bin_prot Char.bin_reader_t t (* static permission tests; see above *) TEST = Char.(=) 'a' (char (of_string "a" : (_, seek) Iobuf.t)) TEST = Char.(=) 'a' (char (of_string "a" : (read, _) Iobuf.t)) TEST = Char.(=) 'a' (char (of_string "a" : (read_write, _) Iobuf.t)) end) open Consume module To_string = struct open To_string let blito = blito TEST_UNIT = test_consume_to_string blito (* Mostly rely on the [Blit.Make_distinct] testing. *) let blit, unsafe_blit, sub, subo = blit, unsafe_blit, sub, subo end module To_bigstring = struct open To_bigstring let blito = blito TEST_UNIT = test_consume_to_bigstring blito (* Mostly rely on the [Blit.Make_distinct] testing. *) let blit, unsafe_blit, sub, subo = blit, unsafe_blit, sub, subo end type nonrec src = src end TEST_UNIT = let t = create ~len:1 in let c = 'a' in sub_shared t |> (fun t -> Fill.char t c; assert (is_empty t)); assert (Char.equal (Consume.char t) c); assert (is_empty t); ;; TEST_UNIT = List.iter [ 0; 1 ] ~f:(fun pos -> let t = create ~len:10 in IFDEF ARCH_SIXTYFOUR THEN let i = large_int 0x1234 0x5678 0x90AB 0xCDEF in sub_shared t ~pos |> (fun t -> Fill.int64_le t i); assert (i = (sub_shared t ~pos |> Consume.int64_le)); ELSE () ENDIF; let i = 0x1234_5678 in sub_shared t ~pos |> (fun t -> Fill.int32_le t i); assert (i = (sub_shared t ~pos |> Consume.int32_le)); let i = 0x1234 in sub_shared t ~pos |> (fun t -> Fill.int16_le t i); assert (i = (sub_shared t ~pos |> Consume.int16_le)); () ) ;; TEST_UNIT = List.iter strings ~f:(fun s -> let t = of_string s in let s' = Consume.string t in assert (is_empty t); assert (String.equal s s')); ;; (* [Fill.string] ranges *) TEST_UNIT = let s = "hello" in let len = String.length s in let t = create ~len:len in let try_write ?str_pos ?len () : _ Or_error.t = try_with (fun () -> sub_shared t |> (fun t -> Fill.string t s ?str_pos ?len)) in if is_safe then (assert (is_error (try_write ~str_pos:(-1) ())); assert (is_error (try_write ~str_pos:(len + 1) ())); assert (is_error (try_write ~str_pos:0 ~len:(len + 1) ()))); ;; module Blit_consume_and_fill = struct open Blit_consume_and_fill let blit = blit let blito = blito let unsafe_blit = unsafe_blit let blit_via_blito ~src ~dst ~len = blito () ~src ~dst ?src_len:(if len = length src then None else Some len) TEST_UNIT = List.iter [ blit ; unsafe_blit ; blit_via_blito ] ~f:(fun blit -> let t1 = create ~len:100 in let t2 = create ~len:100 in let s = "585038473775210758" in Fill.string t1 s; flip_lo t1; assert (String.equal s (Consume.string t1)); assert (is_empty t1); reset t1; Fill.string t1 s; flip_lo t1; blit ~src:t1 ~dst:t2 ~len:(length t1); flip_lo t2; assert (String.equal s (Consume.string t2)); assert (is_empty t2)) ;; end ;; module Blit_fill = struct open Blit_fill let blit = blit let blito = blito let unsafe_blit = unsafe_blit let blit_via_blito ~src ~src_pos ~dst ~len = blito () ~src ?src_pos:(if src_pos = 0 then None else Some src_pos) ~dst ?src_len:(if len = length src - src_pos then None else Some len) TEST_UNIT = List.iter [ blit ; unsafe_blit ; blit_via_blito ] ~f:(fun blit -> let t1 = of_string "0123456789" in let t2 = of_string "qwertyuiop" in let t3 = of_string "!@#$%^&*()" in <:test_result< string >> (to_string t1) ~expect:"0123456789"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()"; blit ~dst:t1 ~src:t2 ~src_pos:0 ~len:(length t2); <:test_result< string >> (to_string t1) ~expect:""; reset t1; <:test_result< string >> (to_string t1) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()"; blit ~dst:t1 ~src:t3 ~src_pos:4 ~len:4; <:test_result< string >> (to_string t1) ~expect:"tyuiop"; reset t1; <:test_result< string >> (to_string t1) ~expect:"%^&*tyuiop"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()") ;; end ;; module Blit_consume = struct open Blit_consume let blit = blit let blito = blito let unsafe_blit = unsafe_blit let blit_via_blito ~src ~dst ~dst_pos ~len = blito () ~src ~dst ?dst_pos:(if dst_pos = 0 then None else Some dst_pos) ?src_len:(if len = length src then None else Some len) TEST_UNIT = List.iter [ blit ; unsafe_blit ; blit_via_blito ] ~f:(fun blit -> let t1 = of_string "0123456789" in let t2 = of_string "qwertyuiop" in let t3 = of_string "!@#$%^&*()" in <:test_result< string >> (to_string t1) ~expect:"0123456789"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()"; blit ~dst:t1 ~dst_pos:0 ~src:t2 ~len:(length t2); <:test_result< string >> (to_string t2) ~expect:""; reset t2; <:test_result< string >> (to_string t1) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()"; blit ~dst:t1 ~dst_pos:2 ~src:t3 ~len:4; <:test_result< string >> (to_string t3) ~expect:"%^&*()"; reset t3; <:test_result< string >> (to_string t1) ~expect:"qw!@#$uiop"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()") ;; let sub = sub let subo = subo let sub_via_subo src ~len = subo src ?len:(if len = length src then None else Some len) TEST_UNIT = List.iter [ sub ; sub_via_subo ] ~f:(fun sub -> let t1 = of_string "0123456789" in let t2 = sub t1 ~len:(length t1) in <:test_result< string >> (to_string t1) ~expect:""; reset t1; let t3 = sub t1 ~len:4 in <:test_result< string >> (to_string t1) ~expect:"456789"; reset t1; <:test_result< string >> (to_string t1) ~expect:"0123456789"; <:test_result< string >> (to_string t2) ~expect:"0123456789"; <:test_result< string >> (to_string t3) ~expect:"0123"; Poke.string t1 ~pos:0 "qwertyuiop"; Poke.string t2 ~pos:0 "!@#$%^&*()"; Poke.string t3 ~pos:0 "asdf"; <:test_result< string >> (to_string t1) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t2) ~expect:"!@#$%^&*()"; <:test_result< string >> (to_string t3) ~expect:"asdf") ;; end ;; module Blit = struct open Blit type nonrec 'rw t_no_seek = 'rw t_no_seek let blit = blit let blito = blito let unsafe_blit = unsafe_blit let blit_via_blito ~src ~src_pos ~dst ~dst_pos ~len = blito () ~src ?src_pos:(if src_pos = 0 then None else Some src_pos) ~dst ?dst_pos:(if dst_pos = 0 then None else Some dst_pos) ?src_len:(if len = length src - src_pos then None else Some len) TEST_UNIT = List.iter [ blit ; unsafe_blit ; blit_via_blito ] ~f:(fun blit -> let t1 = of_string "0123456789" in let t2 = of_string "qwertyuiop" in let t3 = of_string "!@#$%^&*()" in <:test_result< string >> (to_string t1) ~expect:"0123456789"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()"; blit ~dst:t1 ~dst_pos:0 ~src:t2 ~src_pos:0 ~len:(length t2); <:test_result< string >> (to_string t1) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()"; blit ~dst:t1 ~dst_pos:2 ~src:t3 ~src_pos:4 ~len:4; <:test_result< string >> (to_string t1) ~expect:"qw%^&*uiop"; <:test_result< string >> (to_string t2) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t3) ~expect:"!@#$%^&*()") ;; TEST_UNIT = List.iter [ blit ; unsafe_blit ; blit_via_blito ] ~f:(fun blit -> let s = "01234567899876543210" in let t = create ~len:(String.length s) in Iobuf.sub_shared t |> (fun t -> Fill.string t s); blit ~src:t ~dst:t ~src_pos:0 ~dst_pos:10 ~len:10; let s2 = to_string t in assert (String.equal s2 "01234567890123456789")) ;; let sub = sub let subo = subo let sub_via_subo src ~pos ~len = subo src ?pos:(if pos = 0 then None else Some pos) ?len:(if len = length src - pos then None else Some len) TEST_UNIT = List.iter [ sub ; sub_via_subo ] ~f:(fun sub -> let t1 = of_string "0123456789" in let t2 = sub t1 ~pos:0 ~len:(length t1) in let t3 = sub t1 ~pos:3 ~len:4 in <:test_result< string >> (to_string t1) ~expect:"0123456789"; <:test_result< string >> (to_string t2) ~expect:"0123456789"; <:test_result< string >> (to_string t3) ~expect: "3456"; Poke.string t1 ~pos:0 "qwertyuiop"; Poke.string t2 ~pos:0 "!@#$%^&*()"; Poke.string t3 ~pos:0 "asdf"; <:test_result< string >> (to_string t1) ~expect:"qwertyuiop"; <:test_result< string >> (to_string t2) ~expect:"!@#$%^&*()"; <:test_result< string >> (to_string t3) ~expect:"asdf") ;; end ;; module Expert = struct let buf = Expert.buf let hi_max = Expert.hi_max let hi = Expert.hi let lo = Expert.lo let lo_min = Expert.lo_min end let read_assume_fd_is_nonblocking = read_assume_fd_is_nonblocking let write_assume_fd_is_nonblocking = write_assume_fd_is_nonblocking TEST_UNIT = iter_examples ~f:(fun t string ~pos -> let n = String.length string in let file, fd = Unix.mkstemp "iobuf_test" in protect ~finally:(fun () -> Unix.unlink file) ~f:(fun () -> sub_shared t ~pos |> (fun t -> Fill.string t string); sub_shared t ~pos ~len:n |> (fun t -> let len_before = Iobuf.length t in write_assume_fd_is_nonblocking t fd; <:test_result< int >> (len_before - Iobuf.length t) ~expect:n ); Unix.close fd; iter_examples ~f:(fun t _ ~pos -> if length t - pos >= String.length string then let fd = Unix.openfile ~mode:[Unix.O_RDONLY] file in sub_shared t ~pos |> (fun t -> let len_before = Iobuf.length t in match Syscall_result.Unit.to_result (read_assume_fd_is_nonblocking t fd) with | Ok () | Error (EAGAIN | EINTR | EWOULDBLOCK) -> <:test_result< int >> (len_before - Iobuf.length t) ~expect:n | Error e -> raise (Unix.Unix_error (e, "read", "")) ); sub_shared t ~pos ~len:n |> (fun t -> assert (String.equal (to_string t) string)); Unix.close fd ) ) ) ;; let pread_assume_fd_is_nonblocking = pread_assume_fd_is_nonblocking let pwrite_assume_fd_is_nonblocking = pwrite_assume_fd_is_nonblocking TEST_UNIT = let s = "000000000011111111112222222222" in let n = String.length s in let t = of_string s in let file, fd = Unix.mkstemp "iobuf_test" in protect ~finally:(fun () -> Unix.unlink file) ~f:(fun () -> sub_shared t ~pos:0 ~len:n |> (fun t -> pwrite_assume_fd_is_nonblocking t fd ~offset:10; assert (Iobuf.is_empty t)); sub_shared t ~pos:0 ~len:10 |> (fun t -> pread_assume_fd_is_nonblocking t fd ~offset:20; assert (Iobuf.is_empty t)); sub_shared t ~pos:0 ~len:10 |> (fun t -> assert (String.equal (to_string t) "1111111111")); Unix.close fd;) ;; let zero_or_wouldblock result = match Unix.Syscall_result.Int.to_result result with | Ok n -> n = 0 | Error (EWOULDBLOCK | EAGAIN) -> true | Error _ -> false ;; let recvfrom_assume_fd_is_nonblocking = recvfrom_assume_fd_is_nonblocking let expect_non_unix_exception f = assert (try ignore (f () : Unix.Syscall_result.Int.t); false with Unix.Unix_error _ as e -> raise e | _ -> true) ;; let recvmmsg_assume_fd_is_nonblocking = recvmmsg_assume_fd_is_nonblocking TEST_UNIT "recvmmsg smoke" = match recvmmsg_assume_fd_is_nonblocking with | Error _ -> () | Ok recvmmsg -> let open Unix in let count = 10 in let fd = socket ~domain:PF_INET ~kind:SOCK_DGRAM ~protocol:0 in bind fd ~addr:(ADDR_INET (Inet_addr.bind_any, 0)); let iobufs = Array.init count ~f:(fun _ -> create ~len:1500) in let srcs = Array.create ~len:count (ADDR_INET (Inet_addr.bind_any, 0)) in let short_srcs = Array.create ~len:(count - 1) (ADDR_INET (Inet_addr.bind_any, 0)) in set_nonblock fd; (* Errors are expected in these smoke tests, where we listen to a random socket. Here, we also don't try to test recvmmsg's behavior, just our wrapper; [is_error] indicates that [recvmmsg] returned -1, whereas other exceptions indicate that our wrapper detected something wrong. We treat the two situations separately. *) assert (recvmmsg fd iobufs ~count ~srcs |> zero_or_wouldblock); assert (recvmmsg fd iobufs |> zero_or_wouldblock); assert (recvmmsg fd iobufs ~count:(count / 2) ~srcs |> zero_or_wouldblock); assert (recvmmsg fd iobufs ~count:0 ~srcs |> zero_or_wouldblock); expect_non_unix_exception (fun () -> recvmmsg fd iobufs ~count:(count + 1)); expect_non_unix_exception (fun () -> recvmmsg fd iobufs ~count:(-1)); expect_non_unix_exception (fun () -> recvmmsg fd iobufs ~srcs:short_srcs); ;; let recvmmsg_assume_fd_is_nonblocking_no_options = recvmmsg_assume_fd_is_nonblocking_no_options TEST_UNIT "recvmmsg smoke" = match recvmmsg_assume_fd_is_nonblocking_no_options with | Error _ -> () | Ok recvmmsg -> let open Unix in let count = 10 in let fd = socket ~domain:PF_INET ~kind:SOCK_DGRAM ~protocol:0 in bind fd ~addr:(ADDR_INET (Inet_addr.bind_any, 0)); let iobufs = Array.init count ~f:(fun _ -> create ~len:1500) in set_nonblock fd; assert (recvmmsg fd iobufs ~count |> zero_or_wouldblock); expect_non_unix_exception (fun () ->recvmmsg fd iobufs ~count:(count + 1)) ;; let send_nonblocking_no_sigpipe = send_nonblocking_no_sigpipe let sendto_nonblocking_no_sigpipe = sendto_nonblocking_no_sigpipe let rec retry_until_ready thunk = try thunk () with Unix.Unix_error ((EWOULDBLOCK | EAGAIN | EINTR), _, _) -> Thread.yield (); retry_until_ready thunk ;; let sendto_and_recvfrom recvfrom recv_fd sendto ~sendto_name = let port = match Unix.getsockname recv_fd with | Unix.ADDR_INET (_, port) -> port | _ -> assert false in let addr = Unix.(ADDR_INET (Inet_addr.localhost, port)) in Result.iter sendto ~f:(fun sendto -> let sender = Thread.create (fun () -> let send_fd = Unix.(socket ~domain:PF_INET ~kind:SOCK_DGRAM ~protocol:0) in iter_examples ~f:(fun t string ~pos:_ -> Fill.string t string; Iobuf.flip_lo t; retry_until_ready (fun () -> Syscall_result.Unit.ok_or_unix_error_exn (sendto t send_fd addr) ~syscall_name:sendto_name); <:test_pred< (_, _) Iobuf.t >> Iobuf.is_empty t )) () in iter_examples ~f:(fun t string ~pos:_ -> ignore (retry_until_ready (fun () -> recvfrom t recv_fd) : Unix.sockaddr); Iobuf.flip_lo t; <:test_result< string >> ~expect:string (Iobuf.to_string t) ); Thread.join sender ) ;; let sends_with_recvfrom recvfrom = let fd = Unix.(socket ~domain:PF_INET ~kind:SOCK_DGRAM ~protocol:0) in Unix.(setsockopt fd SO_REUSEADDR true); Unix.(bind fd ~addr:(ADDR_INET (Inet_addr.bind_any, 0))); Unix.set_nonblock fd; sendto_and_recvfrom recvfrom fd ~sendto_name:"send" (Or_error.map (send_nonblocking_no_sigpipe ()) ~f:(fun send -> fun t fd addr -> Unix.connect fd ~addr; send t fd)); sendto_and_recvfrom recvfrom fd ~sendto_name:"sendto" (sendto_nonblocking_no_sigpipe ()) ;; TEST_UNIT = sends_with_recvfrom recvfrom_assume_fd_is_nonblocking TEST_UNIT = Result.iter recvmmsg_assume_fd_is_nonblocking ~f:(fun recvmmsg -> sends_with_recvfrom (fun t fd -> let addr_before = Unix.(ADDR_INET (Inet_addr.bind_any, 0)) in let srcs = Array.create ~len:1 addr_before in let result = recvmmsg fd ~srcs (Array.create ~len:1 t) |> Unix.Syscall_result.Int.ok_or_unix_error_exn ~syscall_name:"recvmmsg" in assert (result = 1); (* Check that the prototype source address wasn't modified in place. It is expected to have been replaced in the array by a new sockaddr. *) assert (not (phys_equal addr_before srcs.(0))); assert (Pervasives.(<>) addr_before srcs.(0)); srcs.(0) ) ) TEST_UNIT = List.iter [ 0; 1 ] ~f:(fun pos -> let t = create ~len:10 in let i = 0xF234_5678_90AB_CDEFL in Poke.int64_t_le t ~pos i; assert (Peek.int64_t_le t ~pos = i); Poke.int64_t_be t ~pos i; assert (Peek.int64_t_be t ~pos = i); (IFDEF ARCH_SIXTYFOUR THEN let i = large_int 0x1234 0x5678 0x90AB 0xCDEF in Poke.int64_t_le t ~pos (Int64.of_int i); assert (Peek.int64_t_le t ~pos = Int64.of_int i); Poke.int64_t_be t ~pos (Int64.of_int i); assert (Peek.int64_t_be t ~pos = Int64.of_int i); Poke.int64_le t ~pos i; assert (Peek.int64_le t ~pos = i); Poke.int64_be t ~pos i; assert (Peek.int64_be t ~pos = i); ENDIF); let i = 0x1234_5678 in Poke.int32_le t ~pos i; assert (Peek.int32_le t ~pos = i); Poke.int32_be t ~pos i; assert (Peek.int32_be t ~pos = i); Poke.uint32_le t ~pos i; assert (Peek.uint32_le t ~pos = i); Poke.uint32_be t ~pos i; assert (Peek.uint32_be t ~pos = i); let i = 0x1234 in Poke.int16_le t ~pos i; assert (Peek.int16_le t ~pos = i); Poke.int16_be t ~pos i; assert (Peek.int16_be t ~pos = i); Poke.uint16_le t ~pos i; assert (Peek.uint16_le t ~pos = i); Poke.uint16_be t ~pos i; assert (Peek.uint16_be t ~pos = i); let i = 0x12 in Poke.int8 t ~pos i; assert (Peek.int8 t ~pos = i); Poke.uint8 t ~pos i; assert (Peek.uint8 t ~pos = i)) TEST_UNIT = let t = create ~len:1024 in Fill.int8 t 12; Fill.int16_le t 1234; Fill.int32_le t 345678; Fill.char t 'x'; flip_lo t; assert (length t = 8); assert (Consume.int8 t = 12); assert (Consume.int16_le t = 1234); assert (Consume.int32_le t = 345678); assert (Consume.char t = 'x'); ;; (* Create a file of binary length prefixed messages of a known format to read back using the Iobuf module. Part unit test, part usage example and interface exercise... *) let create_sample_file ?(int_size = 2) ?(be = false) ~msgcount = let bstr = Bigstring.create 512 in (* Sometimes use a bigstring buffer, sometimes a char queue, to test the latter and [read_to_fd] symmetrically to [write_from_fd] below. *) let t = create ~len:512 in let filename, fd = Unix.mkstemp "iobuftest" in for i = 0 to (msgcount - 1) do let s = sprintf "MESSAGE %d" i in let len = String.length s in if Random.bool () then let open Bigstring in let set_int = match int_size with | 2 -> if be then unsafe_set_int16_be else unsafe_set_int16_le | 4 -> if be then unsafe_set_int32_be else unsafe_set_int32_le | 8 -> if be then unsafe_set_int64_be else unsafe_set_int64_le | _ -> failwithf "Unknown int size %d" int_size () in set_int bstr ~pos:0 len; Bigstring.From_string.blito ~src:s ~dst:bstr ~dst_pos:int_size (); really_write fd ~len:(len + int_size) bstr else let fill_int = match int_size with | 2 -> if be then Fill.int16_be else Fill.int16_le | 4 -> if be then Fill.int32_be else Fill.int32_le | 8 -> if be then Fill.int64_be else Fill.int64_le | _ -> failwithf "Unknown int size %d" int_size () in fill_int t len; Fill.string t s; flip_lo t; write_assume_fd_is_nonblocking t fd; <:test_pred< (_, _) Iobuf.t >> Iobuf.is_empty t; (* no short writes *) reset t done; Unix.close fd; filename ;; (** Loop through and check all messages in the given file match the expected "MESSAGE %d" format *) let check_msgs ?(int_size = 2) ?(be = false) file = let msg_number = ref 0 in let check_message r = let msg = Consume.string r in let s = sprintf "MESSAGE %d" !msg_number in assert( String.equal s msg ); msg_number := !msg_number + 1 in let fd = Unix.openfile file ~perm:0o600 ~mode:[Unix.O_RDONLY] in let t = create ~len:512 in let rec drain_messages () = let init_len = length t in if init_len > int_size then let consume_int = match int_size with | 2 -> if be then Consume.int16_be else Consume.int16_le | 4 -> if be then Consume.int32_be else Consume.int32_le | 8 -> if be then Consume.int64_be else Consume.int64_le | _ -> failwithf "Unknown int size %d" int_size () in let needed = consume_int t in if length t < needed then begin rewind t; advance t (length t - init_len); assert (length t = init_len); end else begin check_message (sub_shared t ~len:needed); advance t needed; drain_messages (); end in let rec loop_file () = let len_before = length t in begin match read_assume_fd_is_nonblocking t fd |> Syscall_result.Unit.to_result (* doesn't allocate *) with | Error (EAGAIN | EINTR | EWOULDBLOCK) -> () | Error e -> raise (Unix.Unix_error (e, "read", "")) | Ok () -> () end; if len_before > length t then ( flip_lo t; drain_messages (); compact t; loop_file () ) in loop_file (); Unix.close fd; !msg_number ;; TEST_UNIT = let msgcount = 10_000 in List.iter [2; 4; 8] ~f:(fun int_size -> List.iter [false; true] ~f:(fun be -> let filename = create_sample_file ~int_size ~be ~msgcount in protect ~f:(fun () -> assert (check_msgs ~int_size ~be filename = msgcount)) ~finally:(fun () -> Unix.unlink filename))) ;; end include Accessors (struct module Consume = Consume module Fill = Fill module Peek = Peek module Poke = Poke let is_safe = true end) module Unsafe = Accessors (struct include Unsafe let is_safe = false end) end : (* The signature here is to remind us to add a unit test whenever we add a function to [Iobuf]. *) Iobuf) TEST_MODULE = Test (Iobuf_debug.Make ()) (* Ensure against bugs in [Iobuf_debug]. The above tests [Iobuf_debug], with invariants checked, and this tests the straight [Iobuf] module. *) TEST_MODULE = Test (struct include Iobuf let show_messages = ref true end) core-113.00.00/src/iobuf_tests.mli000066400000000000000000000000341256461075500165740ustar00rootroot00000000000000(** Intentionally empty. *) core-113.00.00/src/jane_common.h000066400000000000000000000016611256461075500162100ustar00rootroot00000000000000#ifndef JANE_COMMON_H #define JANE_COMMON_H #if __GNUC__ >= 3 # ifndef inline # define inline inline __attribute__ ((always_inline)) # endif # ifndef __pure # define __pure __attribute__ ((pure)) # endif # ifndef __const # define __const __attribute__ ((const)) # endif # ifndef __malloc # define __malloc __attribute__ ((malloc)) # endif # ifndef __unused # define __unused __attribute__ ((unused)) # endif # ifndef __likely # define likely(x) __builtin_expect (!!(x), 1) # endif # ifndef __unlikely # define unlikely(x) __builtin_expect (!!(x), 0) # endif #else # ifndef inline # define inline # endif # ifndef __pure # define __pure # endif # ifndef __const # define __const # endif # ifndef __malloc # define __malloc # endif # ifndef __unused # define __unused # endif # ifndef __likely # define likely(x) (x) # endif # ifndef __unlikely # define unlikely(x) (x) # endif #endif #endif /* JANE_COMMON_H */ core-113.00.00/src/libcore_stubs.clib000066400000000000000000000004441256461075500172420ustar00rootroot00000000000000# OASIS_START # DO NOT EDIT (digest: 62b0b46fb2b37ed71ccc5c4242ea2570) bigstring_stubs.o crc_stubs.o iobuf_stubs.o linux_ext_stubs.o ocaml_utils_stubs.o recvmmsg.o signal_stubs.o syslog_stubs.o timespec.o time_ns_stubs.o time_stamp_counter_stubs.o unix_stubs.o unix_time_stubs.o # OASIS_STOP core-113.00.00/src/limiter.ml000066400000000000000000000516221256461075500155530ustar00rootroot00000000000000open Core_kernel.Std open Int.Replace_polymorphic_compare module Infinite_or_finite = struct module T = struct type 'a t = | Infinite | Finite of 'a with sexp, bin_io end include T let compare compare t1 t2 = match t1, t2 with | Infinite, Infinite -> 0 | Infinite, Finite _ -> 1 | Finite _, Infinite -> -1 | Finite a, Finite b -> compare a b ;; let map t ~f = match t with | Infinite -> Infinite | Finite v -> Finite (f v) ;; end open Infinite_or_finite.T module type Arith = sig type t val ( + ) : t -> t -> t val ( - ) : t -> t -> t val ( < ) : t -> t -> bool val ( > ) : t -> t -> bool val ( <= ) : t -> t -> bool val ( <> ) : t -> t -> bool val min : t -> t -> t val max : t -> t -> t val zero : t end (* We implement token math using fixed point math so that moving tokens through in_hopper -> in_bucket -> in_flight never results in dropped tokens or rounding errors due to floating point math. *) module Tokens : sig type t with sexp, bin_io, compare module Arith : Arith with type t := t include Arith with type t := t (* the underlying scaling factor used for conversion from fixed <-> float space *) val scaling_factor : Int63.t val of_float_round_up_exn : float -> t val of_float_round_down_exn : float -> t val to_float : t -> float val to_string : t -> string end = struct type t = Int63.t with sexp, bin_io, compare (* The scaling factor effectively sets how small of a sub-job one can ask for. Choosing 10m lets us specify quite high rates as fractional jobs, while leaving us with the ability of having buckets containing about 10 billion jobs. This gives us plenty of space on both sides. *) let scaling_factor = Int63.of_int 10_000_000 let float_scaling_factor = Float.of_int (Int63.to_int_exn scaling_factor) let zero = Int63.of_int 0 let to_string t = Int63.to_string t let of_float_gen round x = match Float.classify x with | Infinite | Nan -> failwithf "cannot convert (%g) into Tokens.t" x () | Normal | Subnormal | Zero -> Int63.of_int (round (x *. float_scaling_factor)) ;; let of_float_round_up_exn = of_float_gen Float.iround_up_exn let of_float_round_down_exn = of_float_gen Float.iround_down_exn let to_float t = Int63.to_float t /. float_scaling_factor module Arith = struct let ( + ) t1 t2 = Int63.(t1 + t2) let ( - ) t1 t2 = Int63.(t1 - t2) let zero = zero include Comparable.Make_binable(Int63) let min = Int63.min let max = Int63.max end include Arith end let gen_fixed_checks fixed_op float_op = let checks = [ (10., 1.) ; (0., 1.) ; (0., 0.4) ; (-1., 1.3) ; (-1., -0.3) ; (-1., 0.3) ] in List.iter checks ~f:(fun (a, b) -> let fixed_a = Tokens.of_float_round_up_exn a in let fixed_b = Tokens.of_float_round_up_exn b in let fixed_result = fixed_op fixed_a fixed_b |> Tokens.to_float in let float_result = float_op a b in let max_diff = 1. /. Int63.to_float Tokens.scaling_factor in let actual_diff = Float.abs (fixed_result -. float_result) in if Float.(>) actual_diff max_diff then failwithf !"Tokens math failure. (a = %g) (b = %g) (fixed_a = %{Tokens}) \ (fixed_b = %{Tokens}) (a op b) = (%g) (a fixed_op b) = (%g)" a b fixed_a fixed_b float_result fixed_result ()) ;; TEST_UNIT "add" = gen_fixed_checks Tokens.( + ) Float.( + ) TEST_UNIT "sub" = gen_fixed_checks Tokens.( - ) Float.( - ) type t = { start_time : Time.t (** The current time of the rate limiter. Note that when this is moved forward, [in_hopper] must be updated accordingly. *) ; mutable time : Time.t (** the amount of time that has passed expressed in token terms, since start_time. *) ; mutable time_in_token_space : Tokens.t Infinite_or_finite.t (** number of tokens in the bucket *) ; mutable in_bucket : Tokens.t (** number of tokens in the hopper. May be [inf] *) ; mutable in_hopper : Tokens.t Infinite_or_finite.t (** Everything that has been taken from bucket but not returned to hopper *) ; mutable in_flight : Tokens.t (** maximum size allowable in the hopper *) ; mutable bucket_size : Tokens.t ; mutable hopper_to_bucket_rate_per_sec : float Infinite_or_finite.t (** see .mli documentation for [set_token_target_level] *) ; mutable token_target_level : Tokens.t Infinite_or_finite.t } with sexp_of, fields, compare let fill_rate_must_be_positive (fill_rate : float Infinite_or_finite.t) = match fill_rate with | Infinite -> () | Finite rate -> if Float.(rate < 0.) then failwithf !"hopper_to_bucket_rate_per_sec (%G) must be >= 0" rate () ;; let in_system t : Tokens.t Infinite_or_finite.t = match t.in_hopper with | Infinite -> Infinite | Finite in_hopper -> Finite Tokens.(t.in_flight + in_hopper + t.in_bucket) ;; let invariant t = let open Tokens.Arith in fill_rate_must_be_positive t.hopper_to_bucket_rate_per_sec; (* bucket is limited to size *) if t.in_bucket > t.bucket_size then failwithf !"amount in_bucket (%{Tokens}) cannot be greater than bucket_size \ (%{Tokens})" t.in_bucket t.bucket_size (); (* sizes must be positive *) if t.bucket_size <= zero then failwithf !"bucket_size (burst_size) (%{Tokens}) must be > 0" t.bucket_size (); if t.in_bucket < zero then failwithf !"in_bucket (%{Tokens}) must be >= 0." t.in_bucket (); begin match t.in_hopper with | Infinite -> () | Finite in_hopper -> if in_hopper < zero then failwithf !"in_hopper (%{Tokens}) must be >= 0." in_hopper (); end; if t.in_flight < zero then failwithf !"in_flight (%{Tokens}) must be >= 0." t.in_flight (); begin match t.hopper_to_bucket_rate_per_sec, t.time_in_token_space with | Infinite, Finite _ | Finite _, Infinite -> failwith "hopper_to_bucket_rate_per_sec can only be infinite if time_in_token_space is \ infinite"; | Infinite, Infinite | Finite _, Finite _ -> () end; begin match t.token_target_level, in_system t with | Infinite, Infinite -> () | Infinite, Finite in_system -> failwithf !"token_target_level is infinite while tokens in system (%{Tokens}) is finite" in_system () | Finite token_target_level, Infinite -> failwithf !"token_target_level (%{Tokens}) is finite and tokens in system is infinite" token_target_level () | Finite token_target_level, Finite in_system -> if token_target_level < zero then failwithf !"token_target_level (%{Tokens}) must be >= 0." token_target_level (); (* max tokens can only exceed the total in the system when we are waiting for excess in_flight tokens to return. *) if in_system > token_target_level then begin match t.in_hopper with | Infinite -> failwithf !"total tokens in_system (Infinite) > token_target_level (%{Tokens})" token_target_level () | Finite in_hopper -> if in_hopper <> zero || t.in_bucket <> zero then failwithf !"total tokens in_system (%{Tokens}) > token_target_level (%{Tokens})" in_system token_target_level () end end; ;; (* this module provides machinery to save and restore the state of a t. It is used below in operations that may leave [t] in an inconsistent state so that invariants are always maintained for t's accessable outside of this module. It's a bit heavy for what it does, but is also robust. *) module Update : sig val protect : t -> (unit -> unit) -> unit end = struct let empty () = { start_time = Time.epoch ; time = Time.epoch ; time_in_token_space = Infinite ; in_bucket = Tokens.zero ; in_hopper = Finite Tokens.zero ; in_flight = Tokens.zero ; bucket_size = Tokens.zero ; hopper_to_bucket_rate_per_sec = Infinite ; token_target_level = Finite Tokens.zero } ;; module T : sig type state val save : t -> state val restore : state -> t -> unit end = struct type state = t let copy t1 t2 = let copy_to_t2 field = match Field.setter field with | None -> failwith "bug in Core.Limiter. Unexpected immutable field" | Some set -> set t2 (Field.get field t1) in Fields.iter (* start time is immutable, and therefore doesn't need to be saved or restored *) ~start_time:(fun _ -> ()) ~time:copy_to_t2 ~time_in_token_space:copy_to_t2 ~in_bucket:copy_to_t2 ~in_hopper:copy_to_t2 ~in_flight:copy_to_t2 ~bucket_size:copy_to_t2 ~hopper_to_bucket_rate_per_sec:copy_to_t2 ~token_target_level:copy_to_t2; ;; let save t = let state = empty () in copy t state; state ;; let restore state t = copy state t end let protect t f = let state = T.save t in try f (); invariant t with | e -> T.restore state t; raise e ;; (* this test ensures that save and restore work as intended and don't throw because we accidentaly added a non-mutable field *) TEST_UNIT = let t = empty () in begin try protect t (fun () -> (* set all the fields to something to check that they all get reset when we hit an exception *) t.time <- Time.now (); t.in_bucket <- Tokens.of_float_round_up_exn 7.; t.in_hopper <- Finite (Tokens.of_float_round_up_exn 7.); t.in_flight <- Tokens.of_float_round_up_exn 7.; t.bucket_size <- Tokens.of_float_round_up_exn 15.; t.hopper_to_bucket_rate_per_sec <- Finite 4.; t.token_target_level <- Finite (Tokens.of_float_round_up_exn 7.); assert false); with | _ -> () end; assert (compare t (empty ()) = 0) ;; end type limiter = t with sexp_of let create_exn ~now ~hopper_to_bucket_rate_per_sec ~bucket_size ~initial_bucket_level ~initial_hopper_level = let in_hopper = Infinite_or_finite.map initial_hopper_level ~f:Tokens.of_float_round_up_exn in let initial_bucket_level = Tokens.of_float_round_up_exn initial_bucket_level in let token_target_level = Infinite_or_finite.map in_hopper ~f:(fun in_hopper -> Tokens.(in_hopper + initial_bucket_level)) in let time_in_token_space = Infinite_or_finite.map hopper_to_bucket_rate_per_sec ~f:(fun _ -> Tokens.zero) in let t = { start_time = now ; time = now ; time_in_token_space ; in_bucket = initial_bucket_level ; in_hopper ; in_flight = Tokens.zero ; bucket_size = Tokens.of_float_round_up_exn bucket_size ; hopper_to_bucket_rate_per_sec ; token_target_level } in invariant t; t ;; (** used for moving tokens from hopper to bucket in response to changes in time. Note that this approximately preserves the sum of in_bucket and in_hopper. *) let move_at_most_from_hopper_to_bucket t max_move = let open Tokens.Arith in let space_in_bucket = max zero (t.bucket_size - t.in_bucket) in let actual_move = match max_move with | Infinite -> space_in_bucket | Finite max_move -> min max_move space_in_bucket in t.in_bucket <- t.in_bucket + actual_move; t.in_hopper <- Infinite_or_finite.map t.in_hopper ~f:(fun in_hopper -> in_hopper - actual_move) ;; (** Computes the number of tokens that would have dropped since start_time given the current rate *) let calculate_time_in_token_space t = Infinite_or_finite.map t.hopper_to_bucket_rate_per_sec ~f:(fun tokens_per_sec -> let time_elapsed_since_start = Time.Span.to_sec (Time.diff t.time t.start_time) in Tokens.of_float_round_down_exn (time_elapsed_since_start *. tokens_per_sec)) ;; (* advances [t]s notion of time, moving tokens from the hopper down into the bucket as dictated by the passage of time and the hopper_to_bucket_rate_per_sec. This function is careful to only move time forward in increments that drop whole numbers of micro-tokens (see Token), otherwise it might be possible for an (admitedly degenerate) program to call advance_time in a tight loop without dropping any tokens at all. *) let advance_time t ~now = let time_before_call = t.time in t.time <- Time.max time_before_call now; match t.time_in_token_space, calculate_time_in_token_space t with | Infinite, Finite _ | Finite _, Infinite -> invariant t; assert false | Infinite, Infinite -> move_at_most_from_hopper_to_bucket t t.in_hopper | Finite previous_time_in_token_space, Finite new_time_in_token_space -> t.time_in_token_space <- Finite new_time_in_token_space; let amount_that_could_fall = (* this will always be >= 0 because time always moves forward *) Tokens.(-) new_time_in_token_space previous_time_in_token_space in let max_move = match t.in_hopper with | Infinite -> amount_that_could_fall | Finite in_hopper -> Tokens.min in_hopper amount_that_could_fall in move_at_most_from_hopper_to_bucket t (Finite max_move); ;; TEST_UNIT "time can only move forward" = let t = create_exn ~now:Time.epoch ~hopper_to_bucket_rate_per_sec:Infinite ~bucket_size:1. ~initial_bucket_level:0. ~initial_hopper_level:Infinite in advance_time t ~now:(Time.add Time.epoch (Time.Span.of_sec 1.)); let expected_time = t.time in advance_time t ~now:Time.epoch; assert (Time.(=) t.time expected_time) ;; let set_hopper_to_bucket_rate_per_sec_exn t ~now rate = Update.protect t (fun () -> advance_time t ~now; t.hopper_to_bucket_rate_per_sec <- rate; t.time_in_token_space <- calculate_time_in_token_space t; (* The only role of this is to fill the bucket in the case that the hopper rate has been set to infinite. Otherwise, this call to [advance_time] has no effect. *) advance_time t ~now) ;; let set_bucket_size_exn t ~now bucket_size = Update.protect t (fun () -> advance_time t ~now; t.bucket_size <- Tokens.of_float_round_up_exn bucket_size) ;; let try_take t ~now amount = let open Tokens.Arith in advance_time t ~now; let amount = Tokens.of_float_round_up_exn amount in if amount > t.bucket_size then `Asked_for_more_than_bucket_size else if amount > t.in_bucket then `Unable else begin t.in_bucket <- t.in_bucket - amount; t.in_flight <- t.in_flight + amount; `Taken end ;; (* when returning tokens to the hopper we diminish in_flight by the amount returned, and then only return tokens to the hopper until: in_system t = token_target_level *) let return_to_hopper t ~now amount = let open Tokens.Arith in let amount = Tokens.of_float_round_up_exn amount in if amount < zero then failwithf !"return_to_hopper passed a negative amount (%{Tokens})" amount (); if amount > t.in_flight then failwithf !"return_to_hopper passed an amount (%{Tokens}) > in_flight (%{Tokens})" amount t.in_flight (); advance_time t ~now; let currently_in_system = in_system t in let amount_to_add = match t.token_target_level, currently_in_system with | Infinite, Finite _ | Finite _, Infinite -> invariant t; assert false | Infinite, Infinite -> amount | Finite token_target_level, Finite currently_in_system -> if currently_in_system <= token_target_level then amount else begin let excess_tokens = currently_in_system - token_target_level in let tokens_to_drop = min amount excess_tokens in amount - tokens_to_drop end in t.in_flight <- t.in_flight - amount; t.in_hopper <- Infinite_or_finite.map t.in_hopper ~f:(fun in_hopper -> in_hopper + amount_to_add) ;; let tokens_may_be_available_when t ~now amount = let open Tokens.Arith in (* Note that because we're rounding up, we may slightly overestimate the required waiting time *) let amount = Tokens.of_float_round_up_exn amount in if amount > t.bucket_size then `Never_because_greater_than_bucket_size else begin advance_time t ~now; let amount_missing = amount - t.in_bucket in if amount_missing <= zero then `At t.time else begin match t.hopper_to_bucket_rate_per_sec with | Infinite -> `When_return_to_hopper_is_called | Finite tokens_per_sec -> let min_seconds_left = Tokens.to_float amount_missing /. tokens_per_sec in let min_time = `At (Time.add t.time (Time.Span.of_sec min_seconds_left)) in match t.in_hopper with | Finite in_hopper -> if amount_missing > in_hopper then `When_return_to_hopper_is_called else min_time | Infinite -> min_time end end ;; let in_bucket t ~now = advance_time t ~now; Tokens.to_float t.in_bucket ;; let in_hopper t ~now = advance_time t ~now; Infinite_or_finite.map t.in_hopper ~f:Tokens.to_float ;; let in_flight t ~now = advance_time t ~now; Tokens.to_float t.in_flight ;; let in_limiter t ~now = Infinite_or_finite.map (in_hopper t ~now) ~f:(fun in_hopper -> in_bucket t ~now +. in_hopper) ;; let in_system t ~now = advance_time t ~now; Infinite_or_finite.map (in_system t) ~f:Tokens.to_float ;; let set_token_target_level_exn t ~now token_target_level = let open Tokens.Arith in Update.protect t (fun () -> advance_time t ~now; begin match token_target_level with | Infinite -> t.token_target_level <- Infinite; t.in_hopper <- Infinite; | Finite token_target_level -> let token_target_level = Tokens.of_float_round_up_exn token_target_level in let target_for_bucket_plus_hopper = max zero (token_target_level - t.in_flight) in t.in_bucket <- min target_for_bucket_plus_hopper t.in_bucket; t.in_hopper <- Finite (target_for_bucket_plus_hopper - t.in_bucket); t.token_target_level <- Finite token_target_level end) ;; let bucket_size t = Tokens.to_float t.bucket_size let hopper_to_bucket_rate_per_sec t = t.hopper_to_bucket_rate_per_sec module Token_bucket = struct type t = limiter let create_exn ~now ~burst_size:bucket_size ~sustained_rate_per_sec:fill_rate ?(initial_bucket_level = 0.) () = create_exn ~now ~bucket_size ~hopper_to_bucket_rate_per_sec:(Finite fill_rate) ~initial_bucket_level ~initial_hopper_level:Infinite ;; let try_take t ~now = try_take t ~now end module Throttled_rate_limiter = struct type t = limiter let create_exn ~now ~burst_size ~sustained_rate_per_sec:fill_rate ~max_concurrent_jobs = let bucket_size = Float.of_int burst_size in let max_concurrent_jobs = Float.of_int max_concurrent_jobs in let initial_bucket_level = Float.min bucket_size max_concurrent_jobs in let initial_hopper_level = Finite (Float.max 0. (max_concurrent_jobs -. initial_bucket_level)) in create_exn ~now ~bucket_size ~hopper_to_bucket_rate_per_sec:(Finite fill_rate) ~initial_bucket_level ~initial_hopper_level ;; let try_start_job t ~now = match try_take t ~now 1. with | `Asked_for_more_than_bucket_size -> assert false (* see create *) | `Taken -> `Start | `Unable -> begin match tokens_may_be_available_when t ~now 1. with | `Never_because_greater_than_bucket_size -> assert false (* see create *) | `When_return_to_hopper_is_called -> `Max_concurrent_jobs_running | `At time -> `Unable_until_at_least time end ;; let finish_job t ~now = return_to_hopper t ~now 1. end module Throttle = struct include Throttled_rate_limiter let create_exn ~now ~max_concurrent_jobs = (* the sustained rate is immediately overridden with set_hopper_to_bucket_rate_per_sec *) let sustained_rate_unused = 1. in let t = create_exn ~now ~burst_size:max_concurrent_jobs ~sustained_rate_per_sec:sustained_rate_unused ~max_concurrent_jobs in set_hopper_to_bucket_rate_per_sec_exn t ~now Infinite; t ;; let try_start_job t ~now = match try_start_job t ~now with | `Start -> `Start | `Max_concurrent_jobs_running -> `Max_concurrent_jobs_running | `Unable_until_at_least _ -> assert false ;; end module Expert = struct let create_exn = create_exn let try_take = try_take let return_to_hopper = return_to_hopper let set_hopper_to_bucket_rate_per_sec_exn = set_hopper_to_bucket_rate_per_sec_exn let tokens_may_be_available_when = tokens_may_be_available_when let set_token_target_level_exn = set_token_target_level_exn let set_bucket_size_exn = set_bucket_size_exn end core-113.00.00/src/limiter.mli000066400000000000000000000214121256461075500157160ustar00rootroot00000000000000(** Implements a token bucket based throttling rate limiter. This module is useful for limiting network clients to a sensible query rate, or in any case where you have jobs that consume a scarce, but replenishable resource. Unlike a standard token bucket limiter this limiter uses two buckets, an available bucket that tokens are taken from and a hopper that tokens are returned to when the client is finished with them. The available bucket is filled from the hopper at a specified fill rate. Most use cases are covered by the [Token_bucket], [Throttle], and [Throttled_rate_limiter] modules, but the [Generic] module provides full access to the module internals. This interface is the simple, non-concurrent interface, and requires machinery on top to implement a specific strategy. See Async_extra for an async-friendly implementation on top of this module. Most functions in this interface take an explicit time as an argument. [now] is expected to be monotonically increasing. [now]'s that are set in the past are effectively moved up to the current time of the bucket. This API allows one to deal with fractional tokens. Note that tokens are divisible into 10k pieces, which limits the effective granularity to which your job request will be rounded. *) open Core_kernel.Std type t with sexp_of type limiter = t with sexp_of module Infinite_or_finite : sig type 'a t = | Infinite | Finite of 'a with sexp, bin_io end (** Implements a basic token bucket based rate limiter. Users of the throttle must successfully call [try_take] before doing work. *) module Token_bucket : sig type t = private limiter val create_exn : now:Time.t -> burst_size:float -> sustained_rate_per_sec:float -> ?initial_bucket_level:float (** Defaults to zero *) -> unit -> t val try_take : t -> now:Time.t -> float -> [ `Taken | `Unable | `Asked_for_more_than_bucket_size ] end (** Implements a basic throttle. Users of the throttle must successfully call [start_job] before beginning work and must call finish_job once, and only once, when a job is completed. *) module Throttle : sig type t = private limiter val create_exn : now:Time.t -> max_concurrent_jobs:int -> t val try_start_job : t -> now:Time.t -> [ `Start | `Max_concurrent_jobs_running ] val finish_job : t -> now:Time.t -> unit end (** A [Throttled_rate_limiter] combines a [Token_bucket] and a [Throttle]. Unlike a [Token_bucket] jobs cannot consume variable numbers of tokens, but the number of outstanding jobs is also limited to [max_concurrent_jobs]. Like a [Throttle] [finish_job] must be called once, and only once when a job is completed. *) module Throttled_rate_limiter : sig type t = private limiter val create_exn : now:Time.t -> burst_size:int -> sustained_rate_per_sec:float -> max_concurrent_jobs:int -> t val try_start_job : t -> now:Time.t -> [ `Start | `Max_concurrent_jobs_running | `Unable_until_at_least of Time.t ] val finish_job : t -> now:Time.t -> unit end (** {5 common read-only operations} *) val bucket_size : t -> float (** tokens available to immediately take *) val in_bucket : t -> now:Time.t -> float (** tokens waiting to drop at the [hopper_to_bucket_rate_per_sec] *) val in_hopper : t -> now:Time.t -> float Infinite_or_finite.t (** tokens that have been taken, but not yet returned *) val in_flight : t -> now:Time.t -> float (** total number of tokens in the limiter [in_hopper + in_bucket] *) val in_limiter : t -> now:Time.t -> float Infinite_or_finite.t (** total number of tokens in the entire system [in_hopper + in_bucket + in_flight] *) val in_system : t -> now:Time.t -> float Infinite_or_finite.t val hopper_to_bucket_rate_per_sec : t -> float Infinite_or_finite.t (** {5 expert operations} *) module Expert : sig (** - [time] is the reference time that other time accepting functions will use when they adjust [now]. It is almost always correct to set this to Time.now. - [hopper_to_bucket_rate_per_sec] bounds the maximum rate at which tokens fall from the hopper into the bucket where they can be taken. - [bucket_size] bounds the number of tokens that the lower bucket can hold. This corresponds to the maximum burst in a standard token bucket setup. - [initial_hopper_level] sets the number of tokens placed into the hopper when the [Limiter] is created. - [initial_bucket_level] sets the number of tokens placed into the bucket when the [Limiter] is created. If this amount exceeds the bucket size it will be silently limited to [bucket_size]. These tunables can be combined in several ways: - to produce a simple rate limiter, where the hopper is given an infinite number of tokens and clients simply take tokens as they are delivered to the bucket. - to produce a rate_limiter that respects jobs that are more than instantaneous. In this case [initial_hopper_level + initial_bucket_level] should be bounded and clients hold tokens for the duration of their work. - to produce a throttle that doesn't limit the rate of jobs at all, but always keeps a max of n jobs running. In this case [hopper_to_bucket_rate_per_sec] should be infinite but the number of tokens in the system [initial_hopper_level + initial_bucket_level] should be bounded. Workers also need to take care to return tokens to the system. In all cases above throttling and rate limiting combine nicely when the unit of work for both is the same (e.g. one token per message). If the unit of work is different (e.g. rate limit base on a number of tokens equal to message size, but throttle base on simple message count) then a single [t] probably cannot be used to get the correct behavior, and two instances should be used with tokens taken from both. *) val create_exn : now:Time.t -> hopper_to_bucket_rate_per_sec:float Infinite_or_finite.t -> bucket_size:float -> initial_bucket_level:float -> initial_hopper_level:float Infinite_or_finite.t -> t (** returns the earliest time when the requested number of tokens could possibly be delivered. There is no guarantee that the requested number of tokens will actually be available at this time. You must call [try_take] to actually attempt to take the tokens. *) val tokens_may_be_available_when : t -> now:Time.t -> float -> [ `At of Time.t | `When_return_to_hopper_is_called | `Never_because_greater_than_bucket_size ] (** attempts to take the given number of tokens from the bucket. [try_take t ~now n] succeeds iff [in_bucket t ~now >= n]. *) val try_take : t -> now:Time.t -> float -> [ `Taken | `Unable | `Asked_for_more_than_bucket_size ] (** return the given number of tokens to the hopper. These tokens will fill the tokens available to [try_take] at the [fill_rate]. Note that if [return] is called on more tokens then have actually been removed, this can cause the number of concurrent jobs to exceed [max_concurrent_jobs]. Note that, due to rounding issues, one should only return precisely the number of tokens that were previously taken. Returning a sum of different values taken previously may or may not work precisely, depending on the specific floating point numbers used. *) val return_to_hopper : t -> now:Time.t -> float -> unit val set_hopper_to_bucket_rate_per_sec_exn : t -> now:Time.t -> float Infinite_or_finite.t -> unit (** sets the target token level for the limiter going forward. If the system has more tokens than the new target already in it then tokens will be removed (first from the hopper, and then from the bucket) to meet the new maximum. If the target cannot be satisfied by removing tokens from the bucket and hopper (i.e. in_flight is, itself, greater than the new target) the hopper and the bucket will be emptied, and future calls to [return_to_hopper] will drop tokens until the total number of tokens in the system matches the new target. Conversely, if [in_hopper + in_bucket + in_flight] is less than the new target tokens will be added to the hopper such that [in_hopper + in_bucket + in_flight] = the new max. NOTE: you should consider calling set_bucket_size after calling set_token_target_level as the bucket_size is often set to a number related to the number of tokens in the system. *) val set_token_target_level_exn : t -> now:Time.t -> float Infinite_or_finite.t -> unit val set_bucket_size_exn : t -> now:Time.t -> float -> unit end include Invariant.S with type t := t core-113.00.00/src/limiter_unit_tests.ml000066400000000000000000000145151256461075500200340ustar00rootroot00000000000000open Core_kernel.Std module Step_test = struct let offset off = Time.add Time.epoch (Time.Span.of_sec off) type step = | Take of float * bool | Fill of float with sexp type timed_step = (float * step) with sexp let take time amount expect = (time,Take (amount,expect)) let fill time amount = (time,Fill amount) let run t l = try List.iter l ~f:(fun (now_offset, step) -> Limiter.invariant t; let now = offset now_offset in begin match step with | Fill amount -> Limiter.Expert.return_to_hopper t ~now (Float.abs amount) | Take (amount,expect) -> match Limiter.Expert.try_take t ~now amount with | `Asked_for_more_than_bucket_size -> failwithf !"test asked to take more (%g) than bucket size (%{Sexp}) at time %f" amount (Limiter.sexp_of_t t) now_offset () | `Taken -> if not expect then failwithf !"incorrectly able to take %g from the bucket (%{Sexp}) at time %f" amount (Limiter.sexp_of_t t) now_offset (); | `Unable -> if expect then failwithf !"unable to take %g from the bucket (%{Sexp}) at time %f" amount (Limiter.sexp_of_t t) now_offset () end; Limiter.invariant t) with e -> Error.raise (Error.tag_arg (Error.of_exn e) "Limiter step test failed" (t,l) <:sexp_of< Limiter.t * timed_step list>>) ;; TEST_UNIT "return_to_hopper invariants" = let t = Limiter.Expert.create_exn ~now:Time.epoch ~hopper_to_bucket_rate_per_sec:Infinite ~bucket_size:10. ~initial_bucket_level:10. ~initial_hopper_level:(Finite 0.) in <:test_result> ~expect:true (Exn.does_raise (fun () -> Limiter.Expert.return_to_hopper t ~now:Time.epoch 1.)) TEST_UNIT "return_to_hopper after lowering target" = let t = Limiter.Expert.create_exn ~now:Time.epoch ~hopper_to_bucket_rate_per_sec:Infinite ~bucket_size:10. ~initial_bucket_level:10. ~initial_hopper_level:(Finite 0.) in let now = Time.epoch in begin match Limiter.Expert.try_take t ~now 10. with | `Asked_for_more_than_bucket_size | `Unable -> assert false | `Taken -> () end; Limiter.Expert.set_token_target_level_exn t ~now (Finite 5.); Limiter.Expert.return_to_hopper t ~now 6.; <:test_result> ~expect:true (Limiter.in_system t ~now = Finite 5.) TEST_UNIT "return_to_hopper after raising target" = let t = Limiter.Expert.create_exn ~now:Time.epoch ~hopper_to_bucket_rate_per_sec:Infinite ~bucket_size:10. ~initial_bucket_level:10. ~initial_hopper_level:(Finite 0.) in let now = Time.epoch in begin match Limiter.Expert.try_take t ~now 10. with | `Asked_for_more_than_bucket_size | `Unable -> assert false | `Taken -> () end; Limiter.Expert.set_token_target_level_exn t ~now (Finite 15.); Limiter.Expert.return_to_hopper t ~now 6.; <:test_result> ~expect:true (Limiter.in_system t ~now = Finite 15.) TEST_UNIT "Generic" = run (Limiter.Expert.create_exn ~now:Time.epoch ~hopper_to_bucket_rate_per_sec:(Finite (60. /. 60.)) ~bucket_size:60. ~initial_bucket_level:0. ~initial_hopper_level:Infinite) [ take 0.0 1. false ; take 1.0 1. true ; take 1.0 1. false ; take 1.5 1. false ; take 60. 60. false ; take 60. 59. true ] TEST_UNIT "Generic" = run (Limiter.Expert.create_exn ~now:Time.epoch ~hopper_to_bucket_rate_per_sec:(Finite (60. /. 60.)) ~bucket_size:120. ~initial_bucket_level:0. ~initial_hopper_level:Infinite) [ take 0.0 1. false ; take 1.0 1. true ; take 1.0 1. false ; take 1.5 1. false ; take 60. 60. false ; take 360. 120. true ] TEST_UNIT "Generic" = run (Limiter.Expert.create_exn ~now:Time.epoch ~hopper_to_bucket_rate_per_sec:(Finite (60. /. 60.)) ~bucket_size:60. ~initial_bucket_level:0. ~initial_hopper_level:(Finite 10.)) [ take 1. 1. true ; fill 1. 1. ; take 10. 9. true ; fill 10. 9. ; take 11. 1. true ; fill 11. 1. ; take 15. 5. false ; take 15. 4. true ; fill 15. 4. ; take 30. 11. false ; take 30. 10. true ] ;; TEST_UNIT "Throttled_rate_limiter" = let limiter = Limiter.Throttled_rate_limiter.create_exn ~now:Time.epoch ~burst_size:3 ~sustained_rate_per_sec:(2. /. 1.) ~max_concurrent_jobs:5 in run (limiter :> Limiter.t) [ take 0.0 1. true ; take 0.1 1. true ; take 0.2 1. true (* we can open these jobs because of the burst size *) ; take 0.3 1. false (* and now that's done *) ; take 0.5 1. true (* but after 1/2 second, we have another *) ; take 1.0 1. true (* and now one more. We need to wait a bit longer than would be perfect to accomodate token drip granularity. *) ; take 2.0 2. false (* but now there are too many concurrent jobs *) ; fill 2.0 3. (* give some back *) ; take 2.0 1. false (* and it takes time for them to get in the bucket *) ; take 3.0 2. true (* and now we can do a burst of 2 *) ; take 10.0 1. true (* and one more *) ; take 10.0 1. false (* but now we're out of concurrent jobs *) ] ;; TEST_UNIT "Throttle" = let throttle = Limiter.Throttle.create_exn ~now:Time.epoch ~max_concurrent_jobs:3 in run (throttle :> Limiter.t) [ take 0. 1. true ; take 0. 1. true ; take 0. 1. true ; take 0. 1. false ; fill 1. 1. ; take 1. 1. true ] TEST_UNIT "Rounding is reasonble for 1_000_000 elements" = let throttle = Limiter.Throttle.create_exn ~now:Time.epoch ~max_concurrent_jobs:1 in let max_jobs_per_sec = 1_000_000 in let denominator = Float.of_int max_jobs_per_sec in for i = 0 to 2 * max_jobs_per_sec do run (throttle :> Limiter.t) [take 0. (1. /. denominator) (i < max_jobs_per_sec)] done end core-113.00.00/src/limiter_unit_tests.mli000066400000000000000000000000541256461075500201760ustar00rootroot00000000000000(* this interface is deliberately empty *) core-113.00.00/src/linux_ext.ml000066400000000000000000000776261256461075500161410ustar00rootroot00000000000000module Time_ns_in_this_directory = Time_ns open Core_kernel.Std module Time_ns = Time_ns_in_this_directory module File_descr = Core_unix.File_descr module Sysinfo0 = struct type t = { uptime : Span.t; load1 : int; load5 : int; load15 : int; total_ram : int; free_ram : int; shared_ram : int; buffer_ram : int; total_swap : int; free_swap : int; procs : int; totalhigh : int; freehigh : int; mem_unit : int; } with bin_io, sexp end (* If you update this type, you also must update linux_tcpopt_bool, in the C stubs. (And do make sure you get the order correct) *) type tcp_bool_option = TCP_CORK with sexp, bin_io INCLUDE "core_config.mlh" IFDEF POSIX_TIMERS THEN module Clock = struct type t (* These functions should be in Unix, but due to the dependency on Time, this is not possible (cyclic dependency). *) external get_time : t -> float = "unix_clock_gettime" let get_time t = Span.of_float (get_time t) external set_time : t -> float -> unit = "unix_clock_settime" let set_time t s = set_time t (Span.to_float s) external get_resolution : t -> float = "unix_clock_getres" let get_resolution t = Span.of_float (get_resolution t) external get_process_clock : unit -> t = "unix_clock_process_cputime_id_stub" external get_thread_clock : unit -> t = "unix_clock_thread_cputime_id_stub" IFDEF THREAD_CPUTIME THEN external get : Thread.t -> t = "unix_pthread_getcpuclockid" let get = Ok get ELSE let get = Or_error.unimplemented "Linux_ext.Clock.get" ENDIF let get_time = Ok get_time let set_time = Ok set_time let get_resolution = Ok get_resolution let get_process_clock = Ok get_process_clock let get_thread_clock = Ok get_thread_clock end ELSE module Clock = struct type t let get = Or_error.unimplemented "Linux_ext.Clock.get" let get_time = Or_error.unimplemented "Linux_ext.Clock.get_time" let set_time = Or_error.unimplemented "Linux_ext.Clock.set_time" let get_resolution = Or_error.unimplemented "Linux_ext.Clock.get_resolution" let get_process_clock = Or_error.unimplemented "Linux_ext.Clock.get_process_clock" let get_thread_clock = Or_error.unimplemented "Linux_ext.Clock.get_thread_clock" end ENDIF IFDEF TIMERFD THEN module Timerfd = struct module Clock : sig type t with bin_io, compare, sexp val realtime : t val monotonic : t end = struct type t = Int63.t with bin_io, compare, sexp external realtime : unit -> Int63.t = "linux_timerfd_CLOCK_REALTIME" let realtime = realtime () external monotonic : unit -> Int63.t = "linux_timerfd_CLOCK_MONOTONIC" let monotonic = monotonic () end module Flags = struct external nonblock : unit -> Int63.t = "linux_timerfd_TFD_NONBLOCK" let nonblock = nonblock () external cloexec : unit -> Int63.t = "linux_timerfd_TFD_CLOEXEC" let cloexec = cloexec () include Flags.Make (struct let allow_intersecting = false let should_print_error = true let remove_zero_flags = false let known = List.rev [ nonblock, "nonblock"; cloexec, "cloexec"; ] end) end type t = File_descr.t with bin_io, compare, sexp let to_file_descr t = t external timerfd_create : Clock.t -> Flags.t -> int = "linux_timerfd_create" (* At Jane Street, we link with [--wrap timerfd_create] so that we can use our own wrapper around [timerfd_create]. This allows us to compile an executable on a machine that has timerfd (e.g. CentOS 6) but then run the executable on a machine that does not (e.g. CentOS 5), but that has our wrapper library. We set up our wrapper so that when running on a machine that doesn't have it, [timerfd_create] raises ENOSYS. *) let create = let create ?(flags = Flags.empty) clock = File_descr.of_int (timerfd_create clock flags) in match Result.try_with (fun () -> create Clock.realtime) with | Ok t -> (Unix.close t; Ok create) | Error (Unix.Unix_error (Unix.ENOSYS, _, _)) -> Or_error.unimplemented "Linux_ext.Timerfd.create" | Error _ -> (* [timerfd_create] is implemented but fails with the arguments we used above. [create] might still be usable with different arguments, so we expose it here. *) Ok create ;; external unsafe_timerfd_settime : t -> bool -> initial : Int63.t -> interval : Int63.t -> unit = "linux_timerfd_settime" let timerfd_settime t ~absolute ~initial ~interval = (* We could accept [interval < 0] or [initial < 0 when absolute], but then the conversions to timespecs in the C code become tedious and [timerfd_setttime] fails when it gets anything negative anyway. *) if Int63.O.( initial < zero || interval < zero ) then <:raise_structural_sexp< "timerfd_settime got invalid parameters (initial < 0 or interval < 0)." { timerfd = (t : t) ; initial = (initial : Int63.t) ; interval = (interval : Int63.t) } >>; unsafe_timerfd_settime t absolute ~initial ~interval ;; let initial_of_span span = Time_ns.Span.to_int63_ns (if Time_ns.Span.( <= ) span Time_ns.Span.zero then Time_ns.Span.nanosecond else span) ;; let set_at t at = if Time_ns.( <= ) at Time_ns.epoch then failwiths "Timerfd.set_at got time before epoch" at <:sexp_of< Time_ns.t >>; timerfd_settime t ~absolute:true ~initial:(Time_ns.to_int63_ns_since_epoch at) ~interval:Int63.zero let set_after t span = timerfd_settime t ~absolute:false ~initial:(initial_of_span span) ~interval:Int63.zero ;; let set_repeating ?after t interval = if Time_ns.Span.( <= ) interval Time_ns.Span.zero then failwiths "Timerfd.set_repeating got invalid interval" interval <:sexp_of< Time_ns.Span.t >>; let interval = Time_ns.Span.to_int63_ns interval in timerfd_settime t ~absolute:false ~initial:(Option.value_map after ~f:initial_of_span ~default:interval) ~interval ;; let clear t = timerfd_settime t ~absolute:false ~initial:Int63.zero ~interval:Int63.zero type repeat = { fire_after : Time_ns.Span.t ; interval : Time_ns.Span.t } external timerfd_gettime : t -> repeat = "linux_timerfd_gettime" let get t = let spec = timerfd_gettime t in if Time_ns.Span.equal spec.interval Time_ns.Span.zero then if Time_ns.Span.equal spec.fire_after Time_ns.Span.zero then `Not_armed else `Fire_after spec.fire_after else `Repeat spec ;; (* We expect set_after to allocate nothing. *) BENCH_FUN "Linux_ext.Timerfd.set_after" = match create with | Error _ -> ignore | Ok create -> let t = create Clock.realtime in fun () -> set_after t Time_ns.Span.second ;; TEST_MODULE "Linux_ext.Timerfd" = struct TEST_UNIT = match create with | Error _ -> () | Ok create -> let t = create Clock.realtime in assert (get t = `Not_armed); set_after t Time_ns.Span.minute; assert (match get t with | `Fire_after span -> Time_ns.Span.(<=) span Time_ns.Span.minute | _ -> false); let span = Time_ns.Span.scale Time_ns.Span.minute 2. in set_repeating t ~after:Time_ns.Span.minute span; assert (match get t with | `Repeat { fire_after; interval } -> Time_ns.Span.(<=) fire_after Time_ns.Span.minute && Time_ns.Span.equal interval span | _ -> false); ;; end end ELSE module Timerfd = struct module Clock = struct type t = unit with bin_io, compare, sexp let realtime = () let monotonic = () end module Flags = struct let nonblock = Int63.of_int 0o4000 let cloexec = Int63.of_int 0o2000000 include Flags.Make (struct let allow_intersecting = false let should_print_error = true let remove_zero_flags = false let known = List.rev [ nonblock, "nonblock"; cloexec, "cloexec"; ] end) end type t = File_descr.t with bin_io, compare, sexp let to_file_descr t = t type repeat = { fire_after : Time_ns.Span.t; interval : Time_ns.Span.t } let create = Or_error.unimplemented "Linux_ext.Timerfd.create" let set_at _ _ = assert false let set_after _ _ = assert false let set_repeating ?after:_ _ _ = assert false let clear _ = assert false let get _ = assert false end ENDIF (* We use [Int63] rather than [Int] because these flags use 32 bits. *) module Epoll_flags (Flag_values : sig val in_ : Int63.t val out : Int63.t (* val rdhup : Int63.t *) val pri : Int63.t val err : Int63.t val hup : Int63.t val et : Int63.t val oneshot : Int63.t end) = struct let none = Int63.zero include Flag_values include Flags.Make (struct let allow_intersecting = false let should_print_error = true let remove_zero_flags = false let known = [ in_, "in"; out, "out"; (* rdhup, "rdhup"; *) pri, "pri"; err, "err"; hup, "hup"; et, "et"; oneshot, "oneshot"; ] ;; end) end module Priority : sig type t with sexp val equal : t -> t -> bool val of_int : int -> t val to_int : t -> int val incr : t -> t val decr : t -> t end = struct type t = int with sexp let of_int t = t let to_int t = t let incr t = t - 1 let decr t = t + 1 let equal (t : t) t' = t = t' end IFDEF LINUX_EXT THEN type file_descr = Core_unix.File_descr.t external sendfile : sock : file_descr -> fd : file_descr -> pos : int -> len : int -> int = "linux_sendfile_stub" ;; let sendfile ?(pos = 0) ?len ~fd sock = let len = match len with | Some len -> len | None -> (Unix.fstat fd).Unix.st_size - pos in sendfile ~sock ~fd ~pos ~len (* Raw result of sysinfo syscall *) module Raw_sysinfo = struct type t = { uptime : int; load1 : int; load5 : int; load15 : int; total_ram : int; free_ram : int; shared_ram : int; buffer_ram : int; total_swap : int; free_swap : int; procs : int; totalhigh : int; freehigh : int; mem_unit : int; } end module Sysinfo = struct include Sysinfo0 external raw_sysinfo : unit -> Raw_sysinfo.t = "linux_sysinfo" let sysinfo = Ok (fun () -> let raw = raw_sysinfo () in { uptime = Span.of_int_sec raw.Raw_sysinfo.uptime; load1 = raw.Raw_sysinfo.load1; load5 = raw.Raw_sysinfo.load5; load15 = raw.Raw_sysinfo.load15; total_ram = raw.Raw_sysinfo.total_ram; free_ram = raw.Raw_sysinfo.free_ram; shared_ram = raw.Raw_sysinfo.shared_ram; buffer_ram = raw.Raw_sysinfo.buffer_ram; total_swap = raw.Raw_sysinfo.total_swap; free_swap = raw.Raw_sysinfo.free_swap; procs = raw.Raw_sysinfo.procs; totalhigh = raw.Raw_sysinfo.totalhigh; freehigh = raw.Raw_sysinfo.freehigh; mem_unit = raw.Raw_sysinfo.mem_unit; }) end external gettcpopt_bool : file_descr -> tcp_bool_option -> bool = "linux_gettcpopt_bool_stub" external settcpopt_bool : file_descr -> tcp_bool_option -> bool -> unit = "linux_settcpopt_bool_stub" external unsafe_send_nonblocking_no_sigpipe : file_descr -> pos : int -> len : int -> string -> int = "linux_send_nonblocking_no_sigpipe_stub" let unsafe_send_nonblocking_no_sigpipe fd ~pos ~len buf = let res = unsafe_send_nonblocking_no_sigpipe fd ~pos ~len buf in if res = -1 then None else Some res external unsafe_send_no_sigpipe : file_descr -> pos : int -> len : int -> string -> int = "linux_send_no_sigpipe_stub" let check_send_args ?pos ?len buf = let str_len = String.length buf in let pos = match pos with | None -> 0 | Some pos -> if pos < 0 then invalid_arg "send_nonblocking_no_sigpipe: pos < 0"; if pos > str_len then invalid_arg "send_nonblocking_no_sigpipe: pos > str_len"; pos in let len = match len with | None -> str_len - pos | Some len -> if len < 0 then invalid_arg "send_nonblocking_no_sigpipe: pos < 0"; if pos + len > str_len then invalid_arg "send_nonblocking_no_sigpipe: pos + len > str_len"; len in (pos, len) let send_nonblocking_no_sigpipe sock ?pos ?len buf = let (pos, len) = check_send_args ?pos ?len buf in unsafe_send_nonblocking_no_sigpipe sock ~pos ~len buf let send_no_sigpipe sock ?pos ?len buf = let (pos, len) = check_send_args ?pos ?len buf in unsafe_send_no_sigpipe sock ~pos ~len buf external unsafe_sendmsg_nonblocking_no_sigpipe : file_descr -> string Core_unix.IOVec.t array -> int -> int = "linux_sendmsg_nonblocking_no_sigpipe_stub" let unsafe_sendmsg_nonblocking_no_sigpipe fd iovecs count = let res = unsafe_sendmsg_nonblocking_no_sigpipe fd iovecs count in if res = -1 then None else Some res let sendmsg_nonblocking_no_sigpipe sock ?count iovecs = let count = match count with | None -> Array.length iovecs | Some count -> if count < 0 then invalid_arg "sendmsg_nonblocking_no_sigpipe: count < 0"; let n_iovecs = Array.length iovecs in if count > n_iovecs then invalid_arg "sendmsg_nonblocking_no_sigpipe: count > n_iovecs"; count in unsafe_sendmsg_nonblocking_no_sigpipe sock iovecs count external pr_set_pdeathsig : Signal.t -> unit = "linux_pr_set_pdeathsig_stub" external pr_get_pdeathsig : unit -> Signal.t = "linux_pr_get_pdeathsig_stub" external pr_set_name_first16 : string -> unit = "linux_pr_set_name" external pr_get_name : unit -> string = "linux_pr_get_name" let file_descr_realpath fd = Core_filename.realpath ("/proc/self/fd/" ^ File_descr.to_string fd) let out_channel_realpath oc = file_descr_realpath (Unix.descr_of_out_channel oc) let in_channel_realpath ic = file_descr_realpath (Unix.descr_of_in_channel ic) external raw_sched_setaffinity : pid : int -> cpuset : int list -> unit = "linux_sched_setaffinity" let sched_setaffinity ?pid ~cpuset () = let pid = match pid with None -> 0 | Some pid -> Pid.to_int pid in raw_sched_setaffinity ~pid ~cpuset ;; (* defined in unix_stubs.c *) external gettid : unit -> int = "unix_gettid" external setpriority : Priority.t -> unit = "linux_setpriority" external getpriority : unit -> Priority.t = "linux_getpriority" let sched_setaffinity_this_thread ~cpuset = sched_setaffinity ~pid:(Pid.of_int (gettid ())) ~cpuset () ;; let cores = Memo.unit (fun () -> let num_cores = In_channel.with_file "/proc/cpuinfo" ~f:In_channel.input_lines |! List.fold_left ~init:0 ~f:(fun count line -> count + (match String.lsplit2 ~on:':' line with | None -> 0 | Some (label, _) -> if String.(=) (String.rstrip label) "processor" then 1 else 0)) in if num_cores > 0 then num_cores else failwith "Linux_ext.cores: failed to parse /proc/cpuinfo") TEST = cores () > 0 TEST = cores () < 100000 (* 99,999 cores ought to be enough for anybody *) external get_terminal_size : unit -> int * int = "linux_get_terminal_size" external get_ipv4_address_for_interface : string -> string = "linux_get_ipv4_address_for_interface" ;; TEST "lo interface addr is 127.0.0.1" = (* This could false positive if the test box is misconfigured *) get_ipv4_address_for_interface "lo" = "127.0.0.1" (* The C-stub is a simple pass-through of the linux SO_BINDTODEVICE semantics, wherein an empty string removes any binding *) external bind_to_interface' : File_descr.t -> string -> unit = "linux_bind_to_interface" ;; let bind_to_interface fd ifname = let name = match ifname with | `Interface_name name -> name | `Any -> "" in bind_to_interface' fd name ;; module Epoll = struct external flag_epollin : unit -> Int63.t = "linux_epoll_EPOLLIN_flag" external flag_epollout : unit -> Int63.t = "linux_epoll_EPOLLOUT_flag" (* external flag_epollrdhup : unit -> Int63.t = "linux_epoll_EPOLLRDHUP_flag" *) external flag_epollpri : unit -> Int63.t = "linux_epoll_EPOLLPRI_flag" external flag_epollerr : unit -> Int63.t = "linux_epoll_EPOLLERR_flag" external flag_epollhup : unit -> Int63.t = "linux_epoll_EPOLLHUP_flag" external flag_epollet : unit -> Int63.t = "linux_epoll_EPOLLET_flag" external flag_epolloneshot : unit -> Int63.t = "linux_epoll_EPOLLONESHOT_flag" module Flags = Epoll_flags (struct let in_ = flag_epollin () let out = flag_epollout () (* let rdhup = flag_epollrdhup () *) let pri = flag_epollpri () let err = flag_epollerr () let hup = flag_epollhup () let et = flag_epollet () let oneshot = flag_epolloneshot () end) external epoll_create : int -> File_descr.t = "linux_epoll_create" (* Some justification for the below interface: Unlike select() and poll(), epoll() fills in an array of ready events, analogous to a read() call where you pass in a buffer to be filled. Since this is at the core of the I/O loop, we'd like to avoid reallocating that buffer on every call to poll. We're allocating the array on the ocaml side (as a Bigstring), then iterating through it in-place, reducing allocation, copies, and any intermediate lists. For very high message rates and many fds this could be a very beneficial. *) type ready_events = Bigstring.t external epoll_sizeof_epoll_event : unit -> int = "linux_epoll_sizeof_epoll_event" "noalloc" external epoll_offsetof_readyfd : unit -> int = "linux_epoll_offsetof_readyfd" "noalloc" external epoll_offsetof_readyflags : unit -> int = "linux_epoll_offsetof_readyflags" "noalloc" let sizeof_epoll_event = epoll_sizeof_epoll_event () let offsetof_readyfd = epoll_offsetof_readyfd () let offsetof_readyflags = epoll_offsetof_readyflags () external epoll_ctl_add : File_descr.t -> File_descr.t -> Flags.t -> unit = "linux_epoll_ctl_add" external epoll_ctl_mod : File_descr.t -> File_descr.t -> Flags.t -> unit = "linux_epoll_ctl_mod" external epoll_ctl_del : File_descr.t -> File_descr.t -> unit = "linux_epoll_ctl_del" module Table = Bounded_int_table module T = struct type 'a t = { epollfd : File_descr.t; (* [flags_by_fd] has one entry for each file-descr in the epoll set, and stores the epoll flags that the kernel's epoll set currently has for that file-descr. Keeping our own representation of the kernel data structure is useful for debugging, since the information appears in a human-readable way in [sexp_of_t]'s output. It also allows us to hide the distinction between [epoll_ctl_add] and [epoll_ctl_mod], since we know which to use based on whether the file descriptor is already being watched. *) flags_by_fd : (File_descr.t, Flags.t) Table.t; max_ready_events : int; (* [num_ready_events] holds the number of ready events in [ready_events], as determined by the last call to [wait]. *) mutable num_ready_events : int; ready_events : 'a; } with fields, sexp_of end open T let epoll_readyfd t i = Bigstring.unsafe_get_int32_le t ~pos:(i*sizeof_epoll_event + offsetof_readyfd) |> File_descr.of_int ;; let epoll_readyflags t i = Bigstring.unsafe_get_int32_le t ~pos:(i*sizeof_epoll_event + offsetof_readyflags) |> Flags.of_int ;; type in_use = ready_events T.t module Pretty = struct type ready_event = { file_descr : File_descr.t; flags : Flags.t; } with sexp_of type ready_events = ready_event array with sexp_of type t = ready_events T.t with sexp_of end let to_pretty t = { t with ready_events = Array.init t.num_ready_events ~f:(fun i -> { Pretty. file_descr = epoll_readyfd t.ready_events i; flags = epoll_readyflags t.ready_events i; }); } ;; let sexp_of_in_use t = Pretty.sexp_of_t (to_pretty t) type t = [ `Closed | `In_use of in_use ] ref with sexp_of let close t = match !t with | `Closed -> () | `In_use { epollfd; _ } -> t := `Closed; Unix.close epollfd; ;; let invariant t : unit = match !t with | `Closed -> () | `In_use t -> try let check f field = f (Field.get field t) in Fields.iter ~epollfd:ignore ~flags_by_fd:(check (Table.invariant ignore ignore)) ~max_ready_events:(check (fun max_ready_events -> assert (max_ready_events > 0))) ~num_ready_events:(check (fun num_ready -> assert (num_ready >= 0))) ~ready_events:ignore with exn -> failwiths "Epoll.invariant failed" (exn, t) <:sexp_of< exn * in_use >> ;; let create ~num_file_descrs ~max_ready_events = if max_ready_events < 0 then failwiths "Epoll.create got nonpositive max_ready_events" max_ready_events (<:sexp_of< int >>); ref (`In_use { epollfd = epoll_create max_ready_events; flags_by_fd = Table.create ~num_keys:num_file_descrs ~key_to_int:File_descr.to_int ~sexp_of_key:File_descr.sexp_of_t (); max_ready_events; num_ready_events = 0; ready_events = Bigstring.create (sizeof_epoll_event * max_ready_events); }) ;; let in_use_exn t = match !t with | `Closed -> failwith "attempt to use closed epoll set" | `In_use r -> r ;; let use t ~f = f (in_use_exn t) let find t file_descr = use t ~f:(fun t -> Table.find t.flags_by_fd file_descr) let find_exn t file_descr = use t ~f:(fun t -> Table.find_exn t.flags_by_fd file_descr) let iter t ~f = use t ~f:(fun t -> Table.iter t.flags_by_fd ~f:(fun ~key:file_descr ~data:flags -> f file_descr flags)) ;; let set t fd flags = use t ~f:(fun t -> let already_present = Table.mem t.flags_by_fd fd in Table.set t.flags_by_fd ~key:fd ~data:flags; if already_present then epoll_ctl_mod t.epollfd fd flags else epoll_ctl_add t.epollfd fd flags); ;; let remove t fd = use t ~f:(fun t -> if Table.mem t.flags_by_fd fd then epoll_ctl_del t.epollfd fd; Table.remove t.flags_by_fd fd) ;; external epoll_wait : File_descr.t -> ready_events -> int -> int = "linux_epoll_wait" let wait_internal t ~timeout_ms = (* performance hack: [use] requires a closure allocation. *) let t = in_use_exn t in (* We clear [num_ready_events] because [epoll_wait] will invalidate [ready_events], and we don't want another thread to observe [t] and see junk. *) t.num_ready_events <- 0; t.num_ready_events <- epoll_wait t.epollfd t.ready_events timeout_ms; if t.num_ready_events = 0 then `Timeout else `Ok ;; let wait_timeout_after t span = let timeout_ms = if Time_ns.Span.( <= ) span Time_ns.Span.zero then 0 else (* For positive timeouts, we use a minimum timeout of one millisecond, to ensure that we are guaranteed that the timeout has passed when we wake up. If we allowed a positive sub-millisecond timeout, we would round down and end up using a timeout of zero, causing [wait_internal] to return immediately. Such behaviour has been seen to cause Async to spin, repeatedly requesting slightly smaller timeouts. *) let span = Time_ns.Span.max span Time_ns.Span.millisecond in Int63.to_int_exn Time_ns.Span.(div (span + of_int_ns 500_000) (of_int_ns 1_000_000)) in assert (timeout_ms >= 0); wait_internal t ~timeout_ms ;; let wait t ~timeout = (* From the epoll man page: | Specifying a timeout of -1 makes epoll_wait() wait indefinitely, while | specifying a timeout equal to zero makes epoll_wait() to return immediately | even if no events are available (return code equal to zero). *) match timeout with | `Never -> wait_internal t ~timeout_ms:(-1) | `Immediately -> wait_internal t ~timeout_ms:0 | `After span -> wait_timeout_after t span ;; let fold_ready t ~init ~f = use t ~f:(fun t -> let ac = ref init in for i = 0 to t.num_ready_events - 1 do ac := f !ac (epoll_readyfd t.ready_events i) (epoll_readyflags t.ready_events i) done; !ac) ;; let iter_ready t ~f = use t ~f:(fun t -> for i = 0 to t.num_ready_events - 1 do f (epoll_readyfd t.ready_events i) (epoll_readyflags t.ready_events i) done) ;; (* external epoll_pwait * : File_descr.t -> Events_buffer.raw -> int -> int list -> int * = "linux_epoll_pwait" * * let pwait t ~timeout sigs = * let millis = Float.iround_exn ~dir:`Zero ( Span.to_ms timeout ) in * let num_ready = epoll_pwait t.epollfd t.events millis sigs in * if num_ready = 0 then `Timeout * else `Ok { Ready_fds.num_ready ; events = t.events } * ;; *) let create = Ok create end (* Epoll unit test included here for some example usage. Creates 2 sockets, adds them to an epoll set, sends data to one of them and calls Epoll.wait. The test passes if the resulting Ready_fds set has 1 ready fd, matching the one we sent to, with read, !write, and !error. *) TEST_MODULE = struct module Unix = Core_unix module Flags = Epoll.Flags let udp_listener ~port = let sock = Unix.socket ~domain:Unix.PF_INET ~kind:Unix.SOCK_DGRAM ~protocol:0 in let iaddr = Unix.ADDR_INET (Unix.Inet_addr.localhost, port) in Unix.setsockopt sock Unix.SO_REUSEADDR true; Unix.bind sock ~addr:iaddr; sock ;; let send s buf ~port = let addr = Unix.ADDR_INET (Unix.Inet_addr.localhost, port) in let len = String.length buf in Unix.sendto s ~buf ~pos:0 ~len ~mode:[] ~addr ;; let with_epoll ~f = protectx ~finally:Epoll.close ~f ((Or_error.ok_exn Epoll.create) ~num_file_descrs:1024 ~max_ready_events:256) TEST_UNIT "epoll errors" = with_epoll ~f:(fun t -> let tmp = "temporary-file-for-testing-epoll" in let fd = Unix.openfile tmp ~mode:[Unix.O_CREAT; Unix.O_WRONLY] in (* Epoll does not support ordinary files, and so should fail if you ask it to watch one. *) assert (Result.is_error (Result.try_with (fun () -> Epoll.set t fd Flags.none))); Unix.close fd; Unix.unlink tmp) ;; TEST_UNIT "epoll test" = with_epoll ~f:(fun epset -> let span = Time_ns.Span.of_sec 0.1 in let sock1 = udp_listener ~port:7070 in let sock2 = udp_listener ~port:7071 in Epoll.set epset sock1 Flags.in_; Epoll.set epset sock2 Flags.in_; let _sent = send sock2 "TEST" ~port:7070 in begin match Epoll.wait_timeout_after epset span with | `Timeout -> assert false | `Ok -> let ready = Epoll.fold_ready epset ~init:[] ~f:(fun ac fd flags -> if flags = Flags.in_ then fd :: ac else ac) in (* Explanation of the test: 1) I create two udp sockets, sock1 listening on 7070 and sock2, on 7071 2) These two sockets are both added to epoll for read notification 3) I send a packet, _using_ sock2 to sock1 (who is listening on 7070) 4) epoll_wait should return, with [ sock1 ] ready to be read. *) match ready with | [ sock ] when sock = sock1 -> () | [_] -> failwith "wrong socket is ready" | xs -> failwithf "%d sockets are ready" (List.length xs) () end) ;; TEST_UNIT "Timerfd.set_after small span test" = match Timerfd.create with | Error _ -> () | Ok timerfd_create -> with_epoll ~f:(fun epoll -> let timerfd = timerfd_create Timerfd.Clock.realtime in Epoll.set epoll (timerfd :> File_descr.t) Epoll.Flags.in_; List.iter [ 0; 1 ] ~f:(fun span_ns -> Timerfd.set_after timerfd (Time_ns.Span.of_int_ns span_ns); begin match Epoll.wait epoll ~timeout:`Never with | `Timeout -> assert false | `Ok -> () end); Unix.close (timerfd :> Unix.File_descr.t)) ;; end let cores = Ok cores let file_descr_realpath = Ok file_descr_realpath let get_ipv4_address_for_interface = Ok get_ipv4_address_for_interface let bind_to_interface = Ok bind_to_interface let get_terminal_size = Ok get_terminal_size let gettcpopt_bool = Ok gettcpopt_bool let setpriority = Ok setpriority let getpriority = Ok getpriority let in_channel_realpath = Ok in_channel_realpath let out_channel_realpath = Ok out_channel_realpath let pr_get_name = Ok pr_get_name let pr_get_pdeathsig = Ok pr_get_pdeathsig let pr_set_name_first16 = Ok pr_set_name_first16 let pr_set_pdeathsig = Ok pr_set_pdeathsig let sched_setaffinity = Ok sched_setaffinity let sched_setaffinity_this_thread = Ok sched_setaffinity_this_thread let send_no_sigpipe = Ok send_no_sigpipe let send_nonblocking_no_sigpipe = Ok send_nonblocking_no_sigpipe let sendfile = Ok sendfile let sendmsg_nonblocking_no_sigpipe = Ok sendmsg_nonblocking_no_sigpipe let settcpopt_bool = Ok settcpopt_bool ELSE module Sysinfo = struct include Sysinfo0 let sysinfo = Or_error.unimplemented "Linux_ext.Sysinfo.sysinfo" end let u = Or_error.unimplemented let cores = u "Linux_ext.cores" let file_descr_realpath = u "Linux_ext.file_descr_realpath" let get_ipv4_address_for_interface = u "Linux_ext.get_ipv4_address_for_interface" let bind_to_interface = u "Linux_ext.bind_to_interface" let get_terminal_size = u "Linux_ext.get_terminal_size" let gettcpopt_bool = u "Linux_ext.gettcpopt_bool" let setpriority = u "Linux_ext.setpriority" let getpriority = u "Linux_ext.getpriority" let in_channel_realpath = u "Linux_ext.in_channel_realpath" let out_channel_realpath = u "Linux_ext.out_channel_realpath" let pr_get_name = u "Linux_ext.pr_get_name" let pr_get_pdeathsig = u "Linux_ext.pr_get_pdeathsig" let pr_set_name_first16 = u "Linux_ext.pr_set_name_first16" let pr_set_pdeathsig = u "Linux_ext.pr_set_pdeathsig" let sched_setaffinity = u "Linux_ext.sched_setaffinity" let sched_setaffinity_this_thread = u "Linux_ext.sched_setaffinity_this_thread" let send_no_sigpipe = u "Linux_ext.send_no_sigpipe" let send_nonblocking_no_sigpipe = u "Linux_ext.send_nonblocking_no_sigpipe" let sendfile = u "Linux_ext.sendfile" let sendmsg_nonblocking_no_sigpipe = u "Linux_ext.sendmsg_nonblocking_no_sigpipe" let settcpopt_bool = u "Linux_ext.settcpopt_bool" module Epoll = struct module Flags = Epoll_flags (struct let in_ = Int63.of_int (1 lsl 0) let out = Int63.of_int (1 lsl 1) (* let rdhup = Int63.of_int (1 lsl 2) *) let pri = Int63.of_int (1 lsl 3) let err = Int63.of_int (1 lsl 4) let hup = Int63.of_int (1 lsl 5) let et = Int63.of_int (1 lsl 6) let oneshot = Int63.of_int (1 lsl 7) end) type t = [ `Epoll_is_not_implemented ] with sexp_of let create = Or_error.unimplemented "Linux_ext.Epoll.create" let invariant _ = assert false let close _ = assert false let find _ _ = assert false let find_exn _ _ = assert false let set _ _ _ = assert false let remove _ _ = assert false let iter _ ~f:_ = assert false let wait _ ~timeout:_ = assert false let wait_timeout_after _ _ = assert false let iter_ready _ ~f:_ = assert false let fold_ready _ ~init:_ ~f:_ = assert false (* let pwait _ ~timeout:_ _ = assert false *) end ENDIF core-113.00.00/src/linux_ext.mli000066400000000000000000000371141256461075500162760ustar00rootroot00000000000000open Core_kernel.Std open Core_unix (** Interface to Linux-specific system calls *) (** {2 sysinfo} *) module Sysinfo : sig (** Result of sysinfo syscall (man 2 sysinfo) *) type t = { uptime : Span.t; (** time since boot *) load1 : int; (** load average over the last minute *) load5 : int; (** load average over the last 5 minutes*) load15 : int; (** load average over the last 15 minutes *) total_ram : int; (** total usable main memory *) free_ram : int; (** available memory size *) shared_ram : int; (** amount of shared memory *) buffer_ram : int; (** memory used by buffers *) total_swap : int; (** total swap page size *) free_swap : int; (** available swap space *) procs : int; (** number of current processes *) totalhigh : int; (** Total high memory size *) freehigh : int; (** Available high memory size *) mem_unit : int; (** Memory unit size in bytes *) } with sexp, bin_io val sysinfo : (unit -> t) Or_error.t end (** {2 Filesystem functions} *) (** [sendfile ?pos ?len ~fd sock] sends mmap-able data from file descriptor [fd] to socket [sock] using offset [pos] and length [len]. @return the number of characters actually written. NOTE: if the returned value is unequal to what was requested (= the initial size of the data by default), the system call may have been interrupted by a signal, the source file may have been truncated during operation, or a timeout occurred on the socket during sending. It is currently impossible to find out which of the events above happened. Calling {!sendfile} several times on the same descriptor that only partially accepted data due to a timeout will eventually lead to the unix error [EAGAIN]. @raise Unix_error on Unix-errors. @param default pos = 0 @param default len = length of data (file) associated with descriptor [fd] *) val sendfile : (?pos : int -> ?len : int -> fd : File_descr.t -> File_descr.t -> int) Or_error.t (** {2 Non-portable TCP-functionality} *) type tcp_bool_option = TCP_CORK with sexp, bin_io (** [gettcpopt_bool sock opt] @return the current value of the boolean TCP socket option [opt] for socket [sock]. *) val gettcpopt_bool : (File_descr.t -> tcp_bool_option -> bool) Or_error.t (** [settcpopt_bool sock opt v] sets the current value of the boolean TCP socket option [opt] for socket [sock] to value [v]. *) val settcpopt_bool : (File_descr.t -> tcp_bool_option -> bool -> unit) Or_error.t (** [send_nonblocking_no_sigpipe sock ?pos ?len buf] tries to do a nonblocking send on socket [sock] given buffer [buf], offset [pos] and length [len]. Prevents [SIGPIPE], i.e. raise a Unix-error in that case immediately. @return [Some bytes_written] or [None] if the operation would have blocked. @param pos default = 0 @param len default = [String.length buf - pos] @raise Invalid_argument if the designated buffer range is invalid. @raise Unix_error on Unix-errors. *) val send_nonblocking_no_sigpipe : (File_descr.t -> ?pos : int -> ?len : int -> string -> int option) Or_error.t (** [send_no_sigpipe sock ?pos ?len buf] tries to do a blocking send on socket [sock] given buffer [buf], offset [pos] and length [len]. Prevents [SIGPIPE], i.e. raise a Unix-error in that case immediately. @return the number of bytes written. @param pos default = 0 @param len default = [String.length buf - pos] @raise Invalid_argument if the designated buffer range is invalid. @raise Unix_error on Unix-errors. *) val send_no_sigpipe : (File_descr.t -> ?pos : int -> ?len : int -> string -> int) Or_error.t (** [sendmsg_nonblocking_no_sigpipe sock ?count iovecs] tries to do a nonblocking send on socket [sock] using [count] I/O-vectors [iovecs]. Prevents [SIGPIPE], i.e. raises a Unix-error in that case immediately. @return [Some bytes_written] or [None] if the operation would have blocked. @raise Invalid_argument if the designated ranges are invalid. @raise Unix_error on Unix-errors. *) val sendmsg_nonblocking_no_sigpipe : (File_descr.t -> ?count : int -> string IOVec.t array -> int option) Or_error.t (** {2 Clock functions} *) module Clock : sig type t (* All these functions can raise Unix_error. *) (* returns the CPU-clock associated with the thread *) val get : (Thread.t -> t) Or_error.t val get_time : (t -> Span.t) Or_error.t val set_time : (t -> Span.t -> unit) Or_error.t val get_resolution : (t -> Span.t) Or_error.t (** [get_process_clock] the clock measuring the CPU-time of a process. *) val get_process_clock : (unit -> t) Or_error.t (** [get_thread_clock] the clock measuring the CPU-time of the current thread. *) val get_thread_clock : (unit -> t) Or_error.t end (** {2 Timerfd functions} *) module Timerfd : sig (** Clock used to mark the progress of a timer. *) module Clock : sig type t with bin_io, compare, sexp (** Settable system-wide clock. *) val realtime : t (** Nonsettable clock. It is not affected by manual changes to the system time. *) val monotonic : t end module Flags : sig type t with sexp_of include Flags.S with type t := t val nonblock : t (** [TFD_NONBLOCK] *) val cloexec : t (** [TFD_CLOEXEC] *) end type t = private File_descr.t with bin_io, compare, sexp val to_file_descr : t -> File_descr.t (** [create ?flags clock] creates a new timer file descriptor. With Linux 2.6.26 or earlier [flags] must be empty. *) val create : (?flags:Flags.t -> Clock.t -> t) Or_error.t (** [set_at t at] and [set_after t span] set [t] to fire once, at [at] or after [span]. [set_after] treats [span <= 0] as [span = 1ns]; unlike the underlying system call, [timerfd_settime], it does not clear the timer if [span = 0]. To clear a timerfd, use [Timerfd.clear]. [set_repeating ?after t interval] sets [t] to fire every [interval] starting after [after] (default is [interval]), raising if [interval <= 0]. *) val set_at : t -> Time_ns.t -> unit val set_after : t -> Time_ns.Span.t -> unit val set_repeating : ?after:Time_ns.Span.t -> t -> Time_ns.Span.t -> unit (** [clear t] causes [t] to not fire any more. *) val clear : t -> unit type repeat = { fire_after : Time_ns.Span.t ; interval : Time_ns.Span.t } (** [get t] returns the current state of the timer [t]. *) val get : t -> [ `Not_armed | `Fire_after of Time_ns.Span.t | `Repeat of repeat ] end (** {2 Parent death notifications} *) (** [pr_set_pdeathsig s] sets the signal [s] to be sent to the executing process when its parent dies. NOTE: the parent may have died before or while executing this system call. To make sure that you do not miss this event, you should call {!getppid} to get the parent process id after this system call. If the parent has died, the returned parent PID will be 1, i.e. the init process will have adopted the child. You should then either send the signal to yourself using Unix.kill, or execute an appropriate handler. *) val pr_set_pdeathsig : (Signal.t -> unit) Or_error.t (** [pr_get_pdeathsig ()] get the signal that will be sent to the currently executing process when its parent dies. *) val pr_get_pdeathsig : (unit -> Signal.t) Or_error.t (** {2 Task name} *) (** [pr_set_name_first16 name] sets the name of the executing thread to [name]. Only the first 16 bytes in [name] will be used, the rest is ignored. *) val pr_set_name_first16 : (string -> unit) Or_error.t (** [pr_get_name ()] gets the name of the executing thread. The name is at most 16 bytes long. *) val pr_get_name : (unit -> string) Or_error.t (** {2 Pathname resolution} *) (** [file_descr_realpath fd] @return the canonicalized absolute pathname of the file associated with file descriptor [fd]. @raise Unix_error on errors. *) val file_descr_realpath : (File_descr.t -> string) Or_error.t (** [out_channel_realpath oc] @return the canonicalized absolute pathname of the file associated with output channel [oc]. @raise Unix_error on errors. *) val out_channel_realpath : (out_channel -> string) Or_error.t (** [in_channel_realpath ic] @return the canonicalized absolute pathname of the file associated with input channel [ic]. @raise Unix_error on errors. *) val in_channel_realpath : (in_channel -> string) Or_error.t (** {2 Affinity} *) (* Setting the CPU affinity causes a process to only run on the cores chosen. You can find out how many cores a system has in /proc/cpuinfo. This can be useful in two ways: first, it limits a process to a core so that it won't interfere with processes on other cores. Second, you save time by not moving the process back and forth between CPUs, which sometimes invalidates their cache. See "man sched_setaffinity" for details. *) val sched_setaffinity : (?pid : Pid.t -> cpuset : int list -> unit -> unit) Or_error.t val sched_setaffinity_this_thread : (cpuset : int list -> unit) Or_error.t (** [cores ()] @return the number of cores on the machine. This may be different than the number of cores available to the calling process. *) val cores : (unit -> int) Or_error.t (** [get_terminal_size ()] @return [(rows, cols)], the number of rows and columns of the terminal. *) val get_terminal_size : (unit -> int * int) Or_error.t module Priority : sig (* [Priority.t] is what is usually referred to as the "nice" value of a process. It is also known as the "dynamic" priority. It is used with normal (as opposed to real-time) processes that have static priority zero. See [Unix.Scheduler.set] for setting the static priority. *) type t with sexp val equal : t -> t -> bool val of_int : int -> t val to_int : t -> int val incr : t -> t val decr : t -> t end (** Set the calling thread's priority in the linux scheduler *) val setpriority : (Priority.t -> unit) Or_error.t (** Get the calling thread's priority in the linux scheduler *) val getpriority : (unit -> Priority.t) Or_error.t (* [get_ipv4_address_for_interface "eth0"] returns the IP address assigned to eth0, or throws an exception if no IP address is configured. *) val get_ipv4_address_for_interface : (string -> string) Or_error.t (* [bind_to_interface fd (`Interface_name "eth0")] restricts packets from being received/sent on the given file descriptor [fd] on any interface other than "eth0". Use [bind_to_interface fd `Any] to allow traffic on any interface. The bindings are not cumulative; you may only select one interface, or any. Not to be confused with a traditional BSD sockets API [bind()] call, this Linux-specific socket option ([SO_BINDTODEVICE]) is used for applications on multi-homed machines with specific security concerns. For similar functionality when using multicast, see {!Core_unix.mcast_set_ifname}. *) val bind_to_interface : (File_descr.t -> [ `Any | `Interface_name of string ] -> unit) Or_error.t (** epoll() - a linux I/O multiplexer of the same family as select() or poll(). Its main differences are support for Edge or Level triggered notifications (We're using Level-triggered to emulate select) and much better scaling with the number of file descriptors. See the man pages for a full description of the epoll facility. *) module Epoll : sig module Flags : sig (** An [Epoll.Flags.t] is an immutable set of flags for which one can register interest for a file descriptor. It is implemented as a bitmask, and so all operations (+, -, etc.) are constant time with no allocation. [sexp_of_t] produces a human-readable list of bits, e.g. "(in out)". *) type t with sexp_of include Flags.S with type t := t (* The names of the flags match the man pages. E.g. [in_] = "EPOLLIN", [out] = "EPOLLOUT", etc. *) val none : t (* Associated fd is readable *) val in_ : t (* Associated fd is readable *) val out : t (* Associated fd is writable *) (* val rdhup : t (\* Event flag For detecting tcp half-close *\) *) val pri : t (* Urgent data available *) val err : t (* Error condition (always on, no need to set it) *) val hup : t (* Hang up happened (always on) *) val et : t (* Edge Triggered behavior (see man page) *) val oneshot : t (* one-shot behavior for the associated fd *) end (** An [Epoll.t] maintains a map from [File_descr.t] to [Flags.t], where the domain is the set of file descriptors that one is interested in, and the flags associated with each file descriptor specify the types of events one is interested in being notified about for that file descriptor. Our implementation maintains a user-level table equivalent to the kernel epoll set, so that [sexp_of_t] produces useful human-readable information, and so that we can present our standard table interface. The implementation assumes that one never closes a file descriptor that is the domain of an [Epoll.t], since doing so might remove the fd from the kernel epoll set without the implementation's knowledge. An [Epoll.t] also has a buffer that is used to store the set of ready fds returned by calling [wait]. *) type t with sexp_of val invariant : t -> unit (** [create ~num_file_descrs] creates a new epoll set able to watch file descriptors in \[0, num_file_descrs). Additionally, the set allocates space for reading the ready events when [wait] returns, allowing for up to [max_ready_events] to be returned in a single call to [wait]. *) val create : (num_file_descrs:int -> max_ready_events:int -> t) Or_error.t val close : t -> unit (** map operations *) val find : t -> File_descr.t -> Flags.t option val find_exn : t -> File_descr.t -> Flags.t val set : t -> File_descr.t -> Flags.t -> unit val remove : t -> File_descr.t -> unit val iter : t -> f:(File_descr.t -> Flags.t -> unit) -> unit (** [wait t ~timeout] blocks until at least one file descriptor in [t] is ready for one of the events it is being watched for, or [timeout] passes. [wait] side effects [t] by storing the ready set in it. One can subsequently access the ready set by calling [iter_ready] or [fold_ready]. With [wait ~timeout:(`After span)], [span <= 0] is treated as [0]. If [span > 0], then [span] is rounded to the nearest millisecond, with a minimum value of one millisecond. Note that this method should not be considered thread safe. There is mutable state in [t] that will be changed by invocations to wait that cannot be prevented by mutexes around [wait]. *) val wait : t -> timeout:[ `Never | `Immediately | `After of Time_ns.Span.t ] -> [ `Ok | `Timeout ] (** [wait_timeout_after t span = wait t ~timeout:(`After span)]. [wait_timeout_after] is a performance hack to avoid allocating [`After span]. *) val wait_timeout_after : t -> Time_ns.Span.t -> [ `Ok | `Timeout ] (** [iter_ready] and [fold_ready] iterate over the ready set computed by the last call to [wait]. *) val iter_ready : t -> f:(File_descr.t -> Flags.t -> unit) -> unit val fold_ready : t -> init:'a -> f:('a -> File_descr.t -> Flags.t -> 'a) -> 'a (* pwait -> with the specified sigmask, analogous to pselect *) (* val pwait : t -> timeout:Span.t -> int list -> [ `Ok of Ready_fds.t | `Timeout ] *) end core-113.00.00/src/linux_ext_stubs.c000066400000000000000000000333421256461075500171560ustar00rootroot00000000000000#include #ifdef JSC_LINUX_EXT #define _FILE_OFFSET_BITS 64 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int core_unix_close_durably(int fd); extern struct in_addr core_unix_get_in_addr_for_interface(value v_interface); CAMLprim value linux_sendfile_stub(value v_sock, value v_fd, value v_pos, value v_len) { loff_t pos = Long_val(v_pos); ssize_t ret; caml_enter_blocking_section(); ret = sendfile(Int_val(v_sock), Int_val(v_fd), &pos, Long_val(v_len)); caml_leave_blocking_section(); if (ret == -1) uerror("sendfile", Nothing); return Val_long(ret); } CAMLprim value linux_sysinfo(value __unused v_unit) { struct sysinfo s_info; int ret = sysinfo(&s_info); if (ret == -1) uerror("sysinfo", Nothing); else { value v_res = caml_alloc_small(14, 0); Field(v_res, 0) = Val_long(s_info.uptime); Field(v_res, 1) = Val_long(s_info.loads[0]); Field(v_res, 2) = Val_long(s_info.loads[1]); Field(v_res, 3) = Val_long(s_info.loads[2]); Field(v_res, 4) = Val_long(s_info.totalram); Field(v_res, 5) = Val_long(s_info.freeram); Field(v_res, 6) = Val_long(s_info.sharedram); Field(v_res, 7) = Val_long(s_info.bufferram); Field(v_res, 8) = Val_long(s_info.totalswap); Field(v_res, 9) = Val_long(s_info.freeswap); Field(v_res, 10) = Val_int(s_info.procs); Field(v_res, 11) = Val_long(s_info.totalhigh); Field(v_res, 12) = Val_long(s_info.freehigh); Field(v_res, 13) = Val_int(s_info.mem_unit); return v_res; } } /**/ static int linux_tcpopt_bool[] = { TCP_CORK }; enum option_type { TYPE_BOOL = 0, TYPE_INT = 1, TYPE_LINGER = 2, TYPE_TIMEVAL = 3, TYPE_UNIX_ERROR = 4 }; extern value unix_getsockopt_aux( char *name, enum option_type ty, int level, int option, value v_socket); extern value unix_setsockopt_aux( char *name, enum option_type ty, int level, int option, value v_socket, value v_status); CAMLprim value linux_gettcpopt_bool_stub(value v_socket, value v_option) { int option = linux_tcpopt_bool[Int_val(v_option)]; return unix_getsockopt_aux("getsockopt", TYPE_BOOL, SOL_TCP, option, v_socket); } CAMLprim value linux_settcpopt_bool_stub(value v_socket, value v_option, value v_status) { int option = linux_tcpopt_bool[Int_val(v_option)]; return unix_setsockopt_aux( "setsockopt", TYPE_BOOL, SOL_TCP, option, v_socket, v_status); } /**/ static int nonblocking_no_sigpipe_flag = MSG_DONTWAIT | MSG_NOSIGNAL; CAMLprim value linux_send_nonblocking_no_sigpipe_stub( value v_fd, value v_pos, value v_len, value v_buf) { char *buf = String_val(v_buf) + Long_val(v_pos); ssize_t ret = send(Int_val(v_fd), buf, Long_val(v_len), nonblocking_no_sigpipe_flag); if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) uerror("send_nonblocking_no_sigpipe", Nothing); return Val_long(ret); } CAMLprim value linux_send_no_sigpipe_stub( value v_fd, value v_pos, value v_len, value v_buf) { char *buf = String_val(v_buf) + Long_val(v_pos); ssize_t ret = send(Int_val(v_fd), buf, Long_val(v_len), MSG_NOSIGNAL); if (ret == -1) uerror("send_no_sigpipe", Nothing); return Val_long(ret); } CAMLprim value linux_sendmsg_nonblocking_no_sigpipe_stub( value v_fd, value v_iovecs, value v_count) { int count = Int_val(v_count); ssize_t ret; struct iovec *iovecs = caml_stat_alloc(sizeof(struct iovec) * count); struct msghdr msghdr = { NULL, 0, NULL, 0, NULL, 0, 0 }; msghdr.msg_iov = iovecs; msghdr.msg_iovlen = count; for (--count; count >= 0; --count) { struct iovec *iovec = &iovecs[count]; value v_iovec = Field(v_iovecs, count); value v_iov_base = Field(v_iovec, 0); value v_iov_pos = Field(v_iovec, 1); value v_iov_len = Field(v_iovec, 2); iovec->iov_base = String_val(v_iov_base) + Long_val(v_iov_pos); iovec->iov_len = Long_val(v_iov_len); } ret = sendmsg(Int_val(v_fd), &msghdr, nonblocking_no_sigpipe_flag); caml_stat_free(iovecs); if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) uerror("sendmsg_nonblocking_no_sigpipe", Nothing); return Val_long(ret); } CAMLprim value linux_pr_set_pdeathsig_stub(value v_sig) { int sig = caml_convert_signal_number(Int_val(v_sig)); if (prctl(PR_SET_PDEATHSIG, sig) == -1) uerror("pr_set_pdeathsig", Nothing); return Val_unit; } CAMLprim value linux_pr_get_pdeathsig_stub(value __unused v_unit) { int sig; if (prctl(PR_GET_PDEATHSIG, &sig) == -1) uerror("pr_get_pdeathsig", Nothing); return Val_int(caml_rev_convert_signal_number(sig)); } static void cpulist_to_cpuset(value cpulist, cpu_set_t * cpuset) { value l; CPU_ZERO(cpuset); for (l = cpulist; l != Val_int(0); l = Field(l, 1)) { int cpu = Int_val(Field(l, 0)); CPU_SET(cpu, cpuset); } } CAMLprim value linux_sched_setaffinity(value v_pid, value cpulist) { cpu_set_t set; pid_t pid; pid = Int_val(v_pid); cpulist_to_cpuset(cpulist, &set); if (sched_setaffinity(pid, sizeof(cpu_set_t), &set) != 0) uerror("setaffinity", Nothing); return Val_unit; } CAMLprim value linux_pr_set_name(value v_name) { char *buf = String_val(v_name); if (prctl(PR_SET_NAME, (unsigned long) buf) == -1) uerror("pr_set_name", Nothing); return Val_unit; } CAMLprim value linux_pr_get_name(value __unused v_unit) { char buf[17]; buf[16] = 0; if (prctl(PR_GET_NAME, (unsigned long) buf) == -1) uerror("pr_get_name", Nothing); return caml_copy_string(buf); } CAMLprim value linux_setpriority(value v_priority) { int tid; assert(!Is_block(v_priority)); tid = syscall(SYS_gettid); if (setpriority(PRIO_PROCESS, tid, Long_val(v_priority)) == -1) uerror("setpriority", Nothing); return Val_unit; } CAMLprim value linux_getpriority(value v_unit) { int tid; int old_errno; int priority; assert(v_unit == Val_unit); tid = syscall(SYS_gettid); old_errno = errno; errno = 0; priority = getpriority(PRIO_PROCESS, tid); if (errno != 0) { errno = old_errno; uerror("getpriority", Nothing); } errno = old_errno; return Val_long(priority); } CAMLprim value linux_get_terminal_size(value __unused v_unit) { int fd; struct winsize ws; int ret; value v_res; caml_enter_blocking_section(); fd = open("/dev/tty", O_RDWR); if (fd == -1) { caml_leave_blocking_section(); uerror("get_terminal_size__open", Nothing); } ret = ioctl(fd, TIOCGWINSZ, &ws); if (ret == -1) { int old_errno = errno; (void)core_unix_close_durably(fd); caml_leave_blocking_section(); if (ret == -1) { errno = old_errno; uerror("get_terminal_size__ioctl_close", Nothing); } else { errno = old_errno; uerror("get_terminal_size__ioctl", Nothing); } } ret = core_unix_close_durably(fd); caml_leave_blocking_section(); if (ret == -1) uerror("get_terminal_size__close", Nothing); v_res = caml_alloc_small(2, 0); Field(v_res, 0) = Val_int(ws.ws_row); Field(v_res, 1) = Val_int(ws.ws_col); return v_res; } /* Construct an OCaml string as the IP */ CAMLprim value linux_get_ipv4_address_for_interface(value v_interface) { struct in_addr addr = core_unix_get_in_addr_for_interface(v_interface); return caml_copy_string(inet_ntoa(addr)); } /* * This linux specific socket option is in use for applications that require it * for security reasons. Taking a string argument, it does not fit the sockopt stubs used * for other socket options. */ CAMLprim value linux_bind_to_interface(value v_fd, value v_ifname) { int ret, fd, ifname_len; char *ifname; assert(!Is_block(v_fd)); assert(Is_block(v_ifname) && Tag_val(v_ifname) == String_tag); fd = Int_val(v_fd); ifname = String_val(v_ifname); ifname_len = caml_string_length(v_ifname) + 1; if (ifname_len > IFNAMSIZ) { caml_failwith("linux_bind_to_interface: ifname string too long"); } ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void*)ifname, ifname_len); if (ret < 0) { uerror("bind_to_interface", Nothing); } return Val_unit; } /** Core epoll methods **/ #define EPOLL_FLAG(FLAG) DEFINE_INT63_CONSTANT (linux_epoll_##FLAG##_flag, FLAG) EPOLL_FLAG(EPOLLIN) EPOLL_FLAG(EPOLLOUT) /* EPOLL_FLAG(EPOLLRDHUP) */ EPOLL_FLAG(EPOLLPRI) EPOLL_FLAG(EPOLLERR) EPOLL_FLAG(EPOLLHUP) EPOLL_FLAG(EPOLLET) EPOLL_FLAG(EPOLLONESHOT) CAMLprim value linux_epoll_sizeof_epoll_event(value __unused v_unit) { return Val_long(sizeof(struct epoll_event)); } /* * Don't think too hard about the parameter here, the man pages for epoll indicate * that the size parameter is ignored for current implementations of epoll. */ CAMLprim value linux_epoll_create(value v_size) { int retcode; retcode = epoll_create(Long_val(v_size)); if (retcode == -1) uerror("epoll_create", Nothing); return Val_long(retcode); } static value linux_epoll_ctl(value v_epfd, value v_fd, value v_flags, int operation) { struct epoll_event evt; evt.events = Int63_val(v_flags); evt.data.fd = Long_val(v_fd); if (epoll_ctl(Long_val(v_epfd), operation, Long_val(v_fd), &evt) == -1) uerror("epoll_ctl", Nothing); return Val_unit; } /* * Add and modify seem somewhat duplicative, I'm unsure the result of * adding an fd to a set a second time to change the event flags. Use * mod()... */ CAMLprim value linux_epoll_ctl_add(value v_epfd, value v_fd, value v_flags) { return linux_epoll_ctl(v_epfd, v_fd, v_flags, EPOLL_CTL_ADD); } CAMLprim value linux_epoll_ctl_mod(value v_epfd, value v_fd, value v_flags) { return linux_epoll_ctl(v_epfd, v_fd, v_flags, EPOLL_CTL_MOD); } /* * Some implementations ignore errors in delete, as they occur commonly when * an fd is closed prior to the del() call. close() removes an fd from an * epoll set automatically, so the del() call will fail. */ CAMLprim value linux_epoll_ctl_del(value v_epfd, value v_fd) { if (epoll_ctl(Long_val(v_epfd), EPOLL_CTL_DEL, Long_val(v_fd), NULL) == -1) uerror("epoll_ctl", Nothing); return Val_unit; } CAMLprim value linux_epoll_wait(value v_epfd, value v_array, value v_timeout) { struct epoll_event * evt; int retcode, maxevents; int timeout = Long_val(v_timeout); /* [CAMLparam1] is needed here to ensure that the bigstring does not get finalized during the period when we release the Caml lock, below. */ CAMLparam1(v_array); evt = (struct epoll_event *) Caml_ba_data_val(v_array); maxevents = Caml_ba_array_val(v_array)->dim[0] / sizeof(struct epoll_event); /* * timeout, in milliseconds returns immediately if 0 is given, waits * forever with -1. */ if (timeout == 0) { /* returns immediately, skip enter()/leave() pair */ retcode = epoll_wait(Long_val(v_epfd), evt, maxevents, timeout); } else { caml_enter_blocking_section(); retcode = epoll_wait(Long_val(v_epfd), evt, maxevents, timeout); caml_leave_blocking_section(); } if (retcode == -1) uerror("epoll_wait", Nothing); CAMLreturn(Val_long(retcode)); } /** Offsets and sizes of the resulting ready events array. */ CAMLprim value linux_epoll_offsetof_readyfd(value __unused v_unit) { return Val_int( offsetof(struct epoll_event, data.fd)); } CAMLprim value linux_epoll_offsetof_readyflags(value __unused v_unit) { return Val_int( offsetof(struct epoll_event, events)); } #ifdef JSC_TIMERFD /** timerfd bindings **/ #include /* These values are from timerfd.h. They are not defined in Linux 2.6.26 or earlier. */ #if !defined(TFD_NONBLOCK) # define TFD_NONBLOCK 04000 #endif #if !defined(TFD_CLOEXEC) # define TFD_CLOEXEC 02000000 #endif #define TIMERFD_INT63(X) \ CAMLprim value linux_timerfd_##X(value __unused v_unit) \ { return caml_alloc_int63(X); } TIMERFD_INT63(TFD_NONBLOCK) TIMERFD_INT63(TFD_CLOEXEC) TIMERFD_INT63(CLOCK_REALTIME) TIMERFD_INT63(CLOCK_MONOTONIC) CAMLprim value linux_timerfd_create(value v_clock_id, value v_flags) { int retcode; retcode = timerfd_create(Int63_val(v_clock_id), Int63_val(v_flags)); if (retcode == -1) uerror("timerfd_create", Nothing); return Val_int(retcode); } #define NANOS_PER_SECOND 1000000000 static inline void set_timespec(struct timespec *ts, value v) { uint64_t d = Int63_val(v); ts->tv_sec = (time_t) (d / NANOS_PER_SECOND); ts->tv_nsec = (long) (d - (ts->tv_sec * NANOS_PER_SECOND)); } CAMLprim value linux_timerfd_settime(value v_fd, value v_absolute, value v_initial, value v_interval) { int retcode; struct itimerspec old, new; set_timespec(&new.it_value, v_initial); set_timespec(&new.it_interval, v_interval); retcode = timerfd_settime(Int_val(v_fd), Bool_val(v_absolute) ? TFD_TIMER_ABSTIME : 0, &new, &old); if (retcode == -1) uerror("timerfd_settime", Nothing); return Val_unit; } #define Int63_ns_of_timespec(ts) \ caml_alloc_int63((uint64_t)ts.tv_sec * NANOS_PER_SECOND + (uint64_t)ts.tv_nsec) static value alloc_spec(struct itimerspec *spec) { CAMLparam0(); CAMLlocal1(v_spec); v_spec = caml_alloc_tuple(2); Store_field(v_spec, 0, Int63_ns_of_timespec(spec->it_value)); Store_field(v_spec, 1, Int63_ns_of_timespec(spec->it_interval)); CAMLreturn(v_spec); } CAMLprim value linux_timerfd_gettime(value v_fd) { int retcode; struct itimerspec cur; retcode = timerfd_gettime(Int_val(v_fd), &cur); if (retcode == -1) uerror("timerfd_gettime", Nothing); return alloc_spec(&cur); } #endif /* JSC_TIMERFD */ #endif /* JSC_LINUX_EXT */ core-113.00.00/src/lock_file.ml000066400000000000000000000225361256461075500160370ustar00rootroot00000000000000open Core_kernel.Std open Int.Replace_polymorphic_compare let _ = _squelch_unused_module_warning_ module Unix = Core_unix (* We have reason to believe that lockf doesn't work properly on CIFS mounts. The idea behind requiring both lockf and flock is to prevent programs taking locks on network filesystems where they may not be sound. *) let flock fd = Unix.flock fd Unix.Flock_command.lock_exclusive let lockf ?(mode = Unix.F_TLOCK) fd = try Unix.lockf fd ~mode ~len:Int64.zero; true with | _ -> false let lock fd = (* [lockf] doesn't throw any exceptions, so if an exception is raised from this function, it must have come from [flock]. *) let flocked = flock fd in let lockfed = lockf fd in flocked && lockfed let create ?(message = Pid.to_string (Unix.getpid ())) ?(close_on_exec = true) ?(unlink_on_exit = false) path = let message = sprintf "%s\n" message in (* We use [~perm:0o664] rather than our usual default perms, [0o666], because lock files shouldn't rely on the umask to disallow tampering by other. *) let fd = Unix.openfile path ~mode:[Unix.O_WRONLY; Unix.O_CREAT] ~perm:0o664 in try if lock fd then begin if close_on_exec then Unix.set_close_on_exec fd; if unlink_on_exit then at_exit (fun () -> try Unix.unlink path with _ -> ()); Unix.ftruncate fd ~len:Int64.zero; ignore (Unix.write fd ~buf:message ~pos:0 ~len:(String.length message)); (* we truncated the file, so we need the region lock back. We don't really understand why/if this call is needed, but experimental evidence indicates that we need to do it. *) ignore (lockf fd); true end else begin Unix.close fd; (* releases any locks from [flock] and/or [lockf] *) false end with | e -> Unix.close fd; (* releases any locks from [flock] and/or [lockf] *) raise e let create_exn ?message ?close_on_exec ?unlink_on_exit path = if not (create ?message ?close_on_exec ?unlink_on_exit path) then failwithf "Lock_file.create_exn '%s' was unable to acquire the lock" path () (* no timeout specified = wait indefinitely *) let repeat_with_timeout ?timeout lockf path = match timeout with | None -> let rec loop () = try (lockf path) with | _ -> begin Unix.sleep 1; loop () end in loop () | Some timeout -> let start_time = Time.now () in let rec loop () = try lockf path with | e -> begin let since_start = Time.abs_diff start_time (Time.now ()) in if Time.Span.(since_start > timeout) then failwithf "Lock_file: '%s' timed out waiting for existing lock. \ Last error was %s" path (Exn.to_string e) () else begin Unix.sleep 1; loop () end end in loop () (* default timeout is to wait indefinitely *) let blocking_create ?timeout ?message ?close_on_exec ?unlink_on_exit path = repeat_with_timeout ?timeout (fun path -> create_exn ?message ?close_on_exec ?unlink_on_exit path) path let is_locked path = try let fd = Unix.openfile path ~mode:[Unix.O_RDONLY] ~perm:0o664 in let flocked = flock fd in let lockfed = lockf fd ~mode:Unix.F_TEST in Unix.close fd; (* releases any locks from [flock] and/or [lockf] *) if flocked && lockfed then false else true with | Unix.Unix_error (ENOENT, _, _) -> false | e -> raise e TEST_MODULE = struct let lock_file = Filename.temp_file "lock_file" "unit_test" let () = Unix.unlink lock_file TEST = create lock_file TEST = not (create lock_file) TEST = is_locked lock_file let nolock_file = Filename.temp_file "nolock_file" "unit_test" let () = Unix.unlink nolock_file; (* Create an empty file. *) Unix.close (Unix.openfile nolock_file ~mode:[Unix.O_CREAT; Unix.O_WRONLY]) TEST = (* Check that file exists. *) try ignore (Unix.stat nolock_file); true with Unix.Unix_error (ENOENT, _, _) -> false TEST = not (is_locked nolock_file) end let read_file_and_convert ~of_string path = Option.try_with ( fun () -> In_channel.read_all path |> String.strip |> of_string ) ;; let get_pid path = let of_string string = Int.of_string string |> Pid.of_int in read_file_and_convert ~of_string path ;; module Nfs = struct module Info = struct type t = { host : string; pid : Pid.t; message : string } with sexp end let lock_path path = path ^ ".nfs_lock" let get_info path = let of_string string = Sexp.of_string string |> Info.t_of_sexp in read_file_and_convert ~of_string path ;; let get_hostname_and_pid path = Option.map (get_info path) ~f:(fun info -> (info.Info.host, info.Info.pid)) ;; let get_message path = Option.map (get_info path) ~f:(fun info -> info.Info.message) let unlock_safely_exn ~unlock_myself path = (* Make sure error messages contain a reference to "lock.nfs_lock", which is the actually important file. *) let lock_path = lock_path path in let error s = failwithf "Lock_file.Nfs.unlock_safely_exn: unable to unlock %s: %s" lock_path s () in match Core_sys.file_exists ~follow_symlinks:false lock_path with | `Unknown -> error (sprintf "unable to read %s" lock_path) | `No -> () | `Yes -> match get_hostname_and_pid lock_path with | None -> error "lock file doesn't contain hostname and pid" | Some (locking_hostname, locking_pid) -> let my_pid = Unix.getpid () in let my_hostname = Unix.gethostname () in if String.(<>) my_hostname locking_hostname then error (sprintf "locked from %s, unlock attempted from %s" locking_hostname my_hostname) else (* Check if the process is running: sends signal 0 to pid, which should work if the process is running and is owned by the user running this code. If the process is not owned by the user running this code we should fail to unlock either earlier (unable to read the file) or later (unable to remove the file). *) if (unlock_myself && Pid.(=) locking_pid my_pid) || not (Signal.can_send_to locking_pid) then begin (* We need to be able to recover from situation where [path] does not exist for whatever reason, but [lock_path] is present. Error during unlink of [path] are ignored to be able to cope with this situation and properly clean up stale locks. *) begin try Unix.unlink path with | Unix.Unix_error (ENOENT, _, _) -> () | e -> error (Exn.to_string e) end; try Unix.unlink lock_path with | e -> error (Exn.to_string e) end else error (sprintf "locking process (pid %i) still running on %s" (Pid.to_int locking_pid) locking_hostname) ;; (* See mli for more information on the algorithm we use for locking over NFS. Ensure that you understand it before you make any changes here. *) let create_exn ?(message = "") path = try unlock_safely_exn ~unlock_myself:false path; let fd = Unix.openfile path ~mode:[Unix.O_WRONLY; Unix.O_CREAT] in protect ~finally:(fun () -> Unix.close fd) ~f:(fun () -> Unix.link ~target:path ~link_name:(lock_path path) (); Unix.ftruncate fd ~len:0L; let info = { Info. host = Unix.gethostname (); pid = Unix.getpid (); message } in (* if this fprintf fails, empty lock file would be left behind, and subsequent calls to [Lock_file.Nfs.create_exn] would be unable to figure out that it is stale/corrupt and remove it. So we need to remove it ourselves *) try fprintf (Unix.out_channel_of_descr fd) "%s\n%!" (Sexp.to_string_hum (Info.sexp_of_t info)) with | (Sys_error _) as err -> begin Unix.unlink path; Unix.unlink (lock_path path); raise err end ); at_exit (fun () -> try unlock_safely_exn ~unlock_myself:true path with _ -> ()); with | e -> failwithf "Lock_file.Nfs.create_exn: unable to lock '%s' - %s" path (Exn.to_string e) () ;; let create ?message path = Or_error.try_with (fun () -> create_exn ?message path) (* default timeout is to wait indefinitely *) let blocking_create ?timeout ?message path = repeat_with_timeout ?timeout (fun path -> create_exn ?message path) path ;; let critical_section ?message path ~timeout ~f = blocking_create ~timeout ?message path; Exn.protect ~f ~finally:(fun () -> unlock_safely_exn ~unlock_myself:true path) ;; let unlock_exn path = unlock_safely_exn ~unlock_myself:true path let unlock path = Or_error.try_with (fun () -> unlock_exn path) TEST_MODULE = struct let create_bool path = match create path with Ok () -> true | Error _ -> false let path = Filename.temp_file "lock_file" "unit_test" let () = Unix.unlink path TEST = create_bool path TEST = not (create_bool path) let () = unlock_exn path TEST = create_bool path let () = unlock_exn path end end core-113.00.00/src/lock_file.mli000066400000000000000000000144761256461075500162140ustar00rootroot00000000000000(** Mutual exclusion between processes using flock and lockf. A file is considered locked if either of these mechanisms works. These locks are OS-level but are Local (will not work across computers even if they mount the same directory). *) open Core_kernel.Std (** [create ?close_on_exec ?message path] tries to create a file at [path] containing the text [message], which defaults to the pid of the locking process. It returns true on success, false on failure. Note: there is no way to release the lock or the fd created inside! It will only be released when the process dies. If close_on_exec is false, then the lock will not be released until children created via fork and exec also terminate. If not specified, close_on_exec=true. Note that by default, the lock file is not cleaned up for you when the process exits. If you pass [unlink_on_exit:true], an at_exit handler will be set up to remove the lock-file on program termination. The lock file is created with mode 664, so will not be world-writable even with umask 0. *) val create : ?message : string -> ?close_on_exec : bool (* defaults to true *) -> ?unlink_on_exit : bool (* defaults to false *) -> string -> bool (** [create_exn ?message path] is like [create] except that it throws an exception on failure instead of returning a boolean value *) val create_exn : ?message : string -> ?close_on_exec : bool (* defaults to true *) -> ?unlink_on_exit : bool (* defaults to false *) -> string -> unit (** [blocking_create t] tries to create the lock. If another process holds the lock this function will wait until it is released or until timeout expires. *) val blocking_create : ?timeout : Time.Span.t (* defaults to wait indefinitely *) -> ?message : string -> ?close_on_exec : bool (* defaults to true *) -> ?unlink_on_exit : bool (* defaults to false *) -> string -> unit (** [is_locked path] returns true when the file at [path] exists and is locked, false otherwise. Requires write permission for the lock file. *) val is_locked : string -> bool (** [get_pid path] reads the lock file at [path] and returns the pid in the file. Returns [None] if the file cannot be read, or if the file contains a message that is not an int. *) val get_pid : string -> Pid.t option (** An implementation neutral NFS lock file scheme that relies on the atomicity of link over NFS (see NFS Illustrated, atomicity for more information). Rather than relying on a working traditional advisory lock system over NFS we create a hard link between the file given to the create call and a new file .nfs_lock. This link call is atomic (in that it succeeds or fails) across all systems that have the same filesystem mounted. The link file must be cleaned up on program exit (normally accomplished by an at_exit handler, but see caveats below). There are a few caveats compared to local file locks: - These calls require the locker to have write access to the directory containing the file being locked. - Unlike a normal flock call the lock may not be removed when the calling program exits (in particular if it is killed with SIGKILL). - NFS lock files are non-standard and difficult to reason about. This implementation strives to strike a balance between safety and utility in the common case: - one program per machine - one shared user running the program Use cases outside of this may push on/break assumptions used for easy lock cleanup/taking and may lead to double taking the lock. If you have such an odd use case you should test it carefully/consider a different locking mechanism. *) module Nfs : sig (** [create ?message path] tries to create and lock the file at [path] by creating a hard link to [path].nfs_lock. The contents of [path] will be replaced with a sexp containing the caller's hostname and pid, and the optional [message]. Efforts will be made to release this lock when the calling program exits. But there is no guarantee that this will occur under some types of program crash. If the program crashes without removing the lock file an attempt will be made to clean up on restart by checking the hostname and pid stored in the lockfile. *) val create : ?message : string -> string -> unit Or_error.t (** [create_exn ?message path] like create, but throws an exception when it fails to obtain the lock *) val create_exn : ?message : string -> string -> unit (** [blocking_create ?message path] like create, but sleeps for 1 second between lock attempts and does not return until it succeeds or timeout expires. Timeout defaults to wait indefinitely *) val blocking_create : ?timeout : Time.Span.t -> ?message : string -> string -> unit (** [critical_section ?message ~timeout path ~f] wrap function [f] (including exceptions escaping it) by first locking (using {!blocking_create}) and then unlocking the given lock file. *) val critical_section : ?message : string -> string -> timeout : Time.Span.t -> f : (unit -> 'a) -> 'a (** [get_hostname_and_pid path] reads the lock file at [path] and returns the hostname and path in the file. Returns [None] if the file cannot be read. *) val get_hostname_and_pid : string -> (string * Pid.t) option (** [get_message path] reads the lock file at [path] and returns the message in the file. Returns [None] if the file cannot be read. *) val get_message : string -> string option (** [unlock_exn path] unlocks [path] if [path] was locked from the same host and the pid in the file is either the current pid or not the pid of a running process. It will raise if for some reason the lock at the given path cannot be unlocked, for example if the lock is taken by somebody else that is still alive on the same box, or taken by a process on a different host, or unix permissions issues, etc. This function should be used only by programs that need to release their lock before exiting. If releasing the lock can or should wait till the end of the running process, do not call this function -- this library already takes care of releasing at exit all the locks taken. *) val unlock_exn : string -> unit val unlock : string -> unit Or_error.t end core-113.00.00/src/make_substring.ml000066400000000000000000000000431256461075500171120ustar00rootroot00000000000000include Core_kernel.Make_substring core-113.00.00/src/memo.ml000066400000000000000000000000311256461075500150270ustar00rootroot00000000000000include Core_kernel.Memo core-113.00.00/src/monad.ml000066400000000000000000000000321256461075500151710ustar00rootroot00000000000000include Core_kernel.Monad core-113.00.00/src/month.ml000066400000000000000000000000321256461075500152200ustar00rootroot00000000000000include Core_kernel.Month core-113.00.00/src/mutex0.ml000066400000000000000000000017711256461075500153300ustar00rootroot00000000000000open Core_kernel.Std (* Error-checking mutexes. *) include Mutex (** [create] like {!Mutex.create}, but creates an error-checking mutex. Locking a mutex twice from the same thread, unlocking an unlocked mutex, or unlocking a mutex not held by the thread will result in a [Sys_error] exception. *) external create : unit -> Mutex.t = "unix_create_error_checking_mutex" let create = create let phys_equal = Caml.(==) let equal (t : t) t' = phys_equal t t' let critical_section l ~f = lock l; Exn.protect ~f ~finally:(fun () -> unlock l) let synchronize f = let mtx = create () in let f' x = critical_section mtx ~f:(fun () -> f x) in f' let update_signal mtx cnd ~f = critical_section mtx ~f:(fun () -> let res = f () in Condition.signal cnd; res) let update_broadcast mtx cnd ~f = critical_section mtx ~f:(fun () -> let res = f () in Condition.broadcast cnd; res) let try_lock m = if try_lock m then `Acquired else `Already_held_by_me_or_other core-113.00.00/src/nano_mutex.ml000066400000000000000000000256531256461075500162700ustar00rootroot00000000000000open Core_kernel.Std let ok_exn = Or_error.ok_exn (* A [Blocker.t] is an ordinary mutex and conditional variable used to implement blocking when there is lock contention. *) module Blocker : sig type t with sexp_of val create : unit -> t val critical_section : t -> f:(unit -> 'a) -> 'a val wait : t -> unit val signal : t -> unit val save_unused : t -> unit end = struct (* Our use of mutexes is always via [Mutex.critical_section], so that we always lock them and unlock them from a single thread. So, we use [Mutex0], which is error-checking mutexes, which will catch any use that is not what we expect. *) module Condition = Condition module Mutex = Mutex0 type t = { mutex : Mutex.t sexp_opaque; condition : Condition.t sexp_opaque; } with sexp_of (* We keep a cache of unused blockers, since they are relatively costly to create, and we should never need very many simultaneously. We should never need more blockers than the number of nano mutexes being simultaneously blocked on, which of course is no more than the total number of simultaneous threads. *) let unused : t Thread_safe_queue.t = Thread_safe_queue.create () (* [save_unused t] should be called when [t] is no longer in use, so it can be returned by a future call of [create]. *) let save_unused t = Thread_safe_queue.enqueue unused t let create () = if Thread_safe_queue.length unused > 0 then Thread_safe_queue.dequeue_exn unused else { mutex = Mutex.create (); condition = Condition.create () } ;; let critical_section t ~f = Mutex.critical_section t.mutex ~f let wait t = Condition.wait t.condition t.mutex let signal t = Condition.signal t.condition end (* We represent a nano mutex using an OCaml record. The [id_of_thread_holding_lock] field represents whether the mutex is locked or not, and if it is locked, which thread holds the lock. We do not use an [int option] for performance reasons (doing so slows down lock+unlock by a factor of almost two). Instead, we have [id_of_thread_holding_lock = bogus_thread_id] when the mutex is unlocked. The mutex record has an optional [blocker] field for use when the mutex is contended. We use the OS-level condition variable in [blocker] to [wait] in a thread that desires the lock and to [signal] from a thread that is releasing it. When thinking about the implementation, it is helpful to remember the following desiderata: * Safety -- only one thread can acquire the lock at a time. This is accomplished usng a test-and-set to set [id_of_thread_holding_lock]. * Liveness -- if the mutex is unlocked and some threads are waiting on it, then one of those threads will be woken up and given a chance to acquire it. This is accomplished by only waiting when we can ensure that there will be a [signal] of the condition variable in the future. See the more detailed comment in [lock]. * Performance -- do not spin trying to acquire the lock. This is accomplished by waiting on a condition variable if a lock is contended. *) type t = { mutable id_of_thread_holding_lock : int; mutable num_using_blocker : int; mutable blocker : Blocker.t option; } with fields, sexp_of let invariant t = try assert (t.num_using_blocker >= 0); (* It is the case that if [t.num_using_blocker = 0] then [Option.is_none t.blocker], however the converse does not necessarily hold. The code in [with_blocker] doesn't take care to atomically increment [t.num_using_blocker] and set [t.blocker] to [Some]. It could, but doing so is not necessary for the correctness of of [with_blocker], which only relies on test-and-set of [t.blocker] to make sure there is an agreed-upon winner in the race to create a blocker. *) if t.num_using_blocker = 0 then assert (Option.is_none t.blocker); with exn -> failwiths "invariant failed" (exn, t) <:sexp_of< exn * t >> ;; let equal (t : t) t' = phys_equal t t' let bogus_thread_id = -1 let create () = { id_of_thread_holding_lock = bogus_thread_id; num_using_blocker = 0; blocker = None; } ;; let is_locked t = t.id_of_thread_holding_lock <> bogus_thread_id let current_thread_id () = Thread.id (Thread.self ()) let current_thread_has_lock t = t.id_of_thread_holding_lock = current_thread_id () let recursive_lock_error t = Error.create "attempt to lock mutex by thread already holding it" (current_thread_id (), t) <:sexp_of< int * t >> ;; let try_lock t = (* The following code relies on an atomic test-and-set of [id_of_thread_holding_lock], so that there is a definitive winner in a race between multiple lockers and everybody agrees who acquired the lock. *) let current_thread_id = current_thread_id () in (* BEGIN ATOMIC *) if t.id_of_thread_holding_lock = bogus_thread_id then begin t.id_of_thread_holding_lock <- current_thread_id; (* END ATOMIC *) Ok `Acquired; end else if current_thread_id = t.id_of_thread_holding_lock then Error (recursive_lock_error t) else Ok `Not_acquired ;; let try_lock_exn t = ok_exn (try_lock t) (* [with_blocker t f] runs [f blocker] in a critical section. It allocates a blocker for [t] if [t] doesn't already have one. *) let with_blocker t f = t.num_using_blocker <- t.num_using_blocker + 1; let blocker = match t.blocker with | Some blocker -> blocker | None -> let new_blocker = Blocker.create () in (* We allocate [new_blocker_opt] here because one cannot allocate inside an atomic region. *) let new_blocker_opt = Some new_blocker in let blocker = (* We need the following test-and-set to be atomic so that there is a definitive winner in a race between multiple calls to [with_blocker], so that everybody agrees what the underlying [blocker] is. *) (* BEGIN ATOMIC *) match t.blocker with | Some blocker -> blocker | None -> t.blocker <- new_blocker_opt; new_blocker (* END ATOMIC *) in if not (phys_equal blocker new_blocker) then Blocker.save_unused new_blocker; blocker in protect ~f:(fun () -> Blocker.critical_section blocker ~f:(fun () -> f blocker)) ~finally:(fun () -> (* We need the following decrement-test-and-set to be atomic so that we're sure that the last user of blocker clears it. *) (* BEGIN ATOMIC *) t.num_using_blocker <- t.num_using_blocker - 1; if t.num_using_blocker = 0 then begin t.blocker <- None; (* END ATOMIC *) Blocker.save_unused blocker; end) ;; let rec lock t = (* The following code relies on an atomic test-and-set of [id_of_thread_holding_lock], so that there is a definitive winner in a race between multiple [lock]ers, and everybody agrees who acquired the lock. If [is_locked t], we block the locking thread using [Blocker.wait], until some unlocking thread [Blocker.signal]s us. There is a race between the [wait] and the [signal]. If the unlocking thread signals in between our test of [t.id_of_thread_holding_lock] and our [wait], then our [wait] could miss the signal and block forever. We avoid this race by committing to waiting inside a [with_blocker], which increments [t.num_using_blocker]. If the [signal] occurs before the [with_blocker], then it will have cleared [t.id_of_thread_holding_lock], which we will notice as [not (is_locked t)], and then not [wait], and loop trying to [lock] again. Otherwise, when an [unlock] occurs, it will see that [is_some t.blocker], and will enter a critical section on [blocker]. But then it must wait until our critical section on [blocker] finishes, and hence until our call to [wait] finishes. Hence, the [signal] will occur after the [wait]. The recursive call to [lock] will not spin. It happens either because we just lost the race with an unlocker, in which case the subsequent [lock] will succeed, or we actually had to block because someone is holding the lock. The latter is the overwhelmingly common case. Other threads can change [t.id_of_thread_holding_lock] concurrently with this code. However, no other thread can set it to our [current_thread_id], since threads only ever set [t.id_of_thread_holding_lock] to their current thread id, or clear it. *) let current_thread_id = current_thread_id () in (* BEGIN ATOMIC *) if t.id_of_thread_holding_lock = bogus_thread_id then begin t.id_of_thread_holding_lock <- current_thread_id; (* END ATOMIC *) Result.ok_unit end else if current_thread_id = t.id_of_thread_holding_lock then Error (recursive_lock_error t) else begin with_blocker t (fun blocker -> if is_locked t then Blocker.wait blocker); lock t end; ;; let lock_exn t = ok_exn (lock t) type message = { current_thread_id : int; mutex : t; } with sexp_of let unlock t = let current_thread_id = current_thread_id () in (* We need the following test-and-set to be atomic so that there is a definitive winner in a race between multiple unlockers, so that one unlock succeeds and the rest fail. *) (* BEGIN ATOMIC *) if t.id_of_thread_holding_lock <> bogus_thread_id then begin if t.id_of_thread_holding_lock = current_thread_id then begin t.id_of_thread_holding_lock <- bogus_thread_id; (* END ATOMIC *) if Option.is_some t.blocker then with_blocker t Blocker.signal; Result.ok_unit; end else Error (Error.create "attempt to unlock mutex held by another thread" { current_thread_id; mutex = t } <:sexp_of< message >>) end else Error (Error.create "attempt to unlock an unlocked mutex" { current_thread_id; mutex = t } <:sexp_of< message >>) ;; let unlock_exn t = ok_exn (unlock t) let critical_section t ~f = lock_exn t; protect ~f ~finally:(fun () -> unlock_exn t); ;; TEST_UNIT = let l = create () in lock_exn l; unlock_exn l; match try_lock l with | Ok `Not_acquired | Error _ -> assert false | Ok `Acquired -> unlock_exn l ;; TEST_UNIT = List.iter [ ( 2, 100, 0.); ( 10, 100, 0.); ( 10, 100, 0.001); ( 100, 10, 0.001); ] ~f:(fun (num_threads, num_iterations, pause_for) -> try let l = create () in let am_holding_lock = ref false in let one_thread () = Thread.create (fun () -> for _i = 1 to num_iterations do lock_exn l; if !am_holding_lock then failwith "lock multiply acquired"; am_holding_lock := true; ignore (Core_unix.nanosleep pause_for : float); am_holding_lock := false; unlock_exn l; done) () in let threads = List.init num_threads ~f:(fun _ -> one_thread ()) in List.iter threads ~f:Thread.join with | exn -> failwiths "test failed" (num_threads, num_iterations, pause_for, exn) (<:sexp_of< int * int * float * exn >>)) ;; core-113.00.00/src/nano_mutex.mli000066400000000000000000000073631256461075500164370ustar00rootroot00000000000000 (** A nano-mutex is a lightweight mutex that can be used only within a single OCaml runtime. {1 Performance} =============== Nano-mutexes are intended to be significantly cheaper than OS-level mutexes. Creating a nano-mutex allocates a single OCaml record. Locking and unlocking an uncontested nano-mutex take a handful of instructions. Only if a nano-mutex is contested will it fall back to using an OS-level mutex. If a nano-mutex becomes uncontested again, it will switch back to using an OCaml-only lock. Nano-mutexes can be faster than using OS-level mutexes because OCaml uses a global lock on the runtime, and requires all running OCaml code to hold the lock. The OCaml compiler only allows thread switches at certain points, and we can use that fact to get the atomic test-and-set used in the core of our implementaion without needing any primitive locking, essentially because we're protected by the OCaml global lock. Here are some benchmarks comparing various mutexes available in OCaml: {v |-------------------------------------------------------------| | Name | Run time | S. dev. | Allocated | |----------------------------+----------+---------+-----------+ | Caml.Mutex create | 247 ns | 0 ns | 3 | | Caml.Mutex lock/unlock | 49 ns | 0 ns | 0 | | Core.Mutex create | 698 ns | 0 ns | 3 | | Core.Mutex lock/unlock | 49 ns | 0 ns | 0 | | Nano_mutex create | 10 ns | 0 ns | 4 | | Nano_mutex lock/unlock | 28 ns | 0 ns | 0 | |-------------------------------------------------------------| v} The benchmark code is in core/extended/lib_test/bench_nano_mutex.ml. {1 Error handling} ================== For any mutex, there are design choices as to how to behave in certain situations: - recursive locking (when a thread locks a mutex it already has) - unlocking an unlocked mutex - unlocking a mutex held by another thread Here is a table comparing how the various mutexes behave: {v |--------------------+------------+------------+------------+ | | Caml.Mutex | Core.Mutex | Nano_mutex | |--------------------+------------+------------+------------+ | recursive lock | undefined | error | error | | unlocking unlocked | undefined | error | error | | t1:lock t2:unlock | undefined | error | error | |--------------------+------------+------------+------------+ v} *) open Core_kernel.Std type t with sexp_of val invariant : t -> unit (** [create ()] returns a new, unlocked mutex. *) val create : unit -> t (** [equal] is [phys_equal] *) val equal : t -> t -> bool (** [current_thread_has_lock t] returns [true] iff the current thread has [t] locked. *) val current_thread_has_lock : t -> bool (** [lock t] locks the mutex [t], blocking until it can be locked. [lock] immediately returns [Error] if the current thread already holds [t]. *) val lock : t -> unit Or_error.t val lock_exn : t -> unit (** [try_lock t] locks [t] if it can immediately do so. The result indicates whether [try_lock] succeeded in acquiring the lock. [try_lock] returns [Error] if the current thread already holds [t]. *) val try_lock : t -> [ `Acquired | `Not_acquired ] Or_error.t val try_lock_exn : t -> [ `Acquired | `Not_acquired ] (** [unlock t] unlocks [t], if the current thread holds it. [unlock] returns [Error] if the lock is not held by the calling thread. *) val unlock : t -> unit Or_error.t val unlock_exn : t -> unit val critical_section : t -> f:(unit -> 'a) -> 'a core-113.00.00/src/nanosecond_stat.h000066400000000000000000000005011256461075500170750ustar00rootroot00000000000000#if JSC_STAT_NANOSEC_METHOD == 1 # define NSEC(field) st_##field##tim.tv_nsec #elif JSC_STAT_NANOSEC_METHOD == 2 # define NSEC(field) st_##field##timespec.tv_nsec #elif JSC_STAT_NANOSEC_METHOD == 3 # define NSEC(field) st_##field##timensec #else # error "JSC_STAT_NANOSEC_METHOD must be defined to 1, 2 or 3!" #endif core-113.00.00/src/never_returns.ml000066400000000000000000000000421256461075500167750ustar00rootroot00000000000000include Core_kernel.Never_returns core-113.00.00/src/no_polymorphic_compare.ml000066400000000000000000000000531256461075500206450ustar00rootroot00000000000000include Core_kernel.No_polymorphic_compare core-113.00.00/src/nothing.ml000066400000000000000000000000341256461075500155430ustar00rootroot00000000000000include Core_kernel.Nothing core-113.00.00/src/nothing0.ml000066400000000000000000000000351256461075500156240ustar00rootroot00000000000000include Core_kernel.Nothing0 core-113.00.00/src/ocaml_utils.h000066400000000000000000000033201256461075500162300ustar00rootroot00000000000000#ifndef OCAML_UTILS_H #define OCAML_UTILS_H #include #include #include #include #include #include #include #include #include #include #define XSTR(S) STR(S) #define STR(S) #S #ifdef JSC_ARCH_SIXTYFOUR # define caml_alloc_int63(v) Val_long(v) # define Int63_val(v) Long_val(v) #else # define caml_alloc_int63(v) caml_copy_int64(v) # define Int63_val(v) Int64_val(v) #endif typedef int64_t int63; #define DEFINE_INT63_CONSTANT(name,z) \ CAMLprim value name(value __unused v_unit) { return caml_alloc_int63(z); } /* [strcmp] is defined as a macro in our current compilation environment. We use [strcmp_not_a_macro] instead so that the text of this macro does not overflow the C89 limit on string literal length when used inside [assert]. */ /* defined in ocaml_utils_stubs.c */ extern int strcmp_not_a_macro(const char*, const char*); extern value getsockopt_int(int *tcpopt, value sock, int level, value option); extern value setsockopt_int( int *tcpopt, value sock, int level, value option, value status); extern int caml_convert_signal_number(int signo); extern int caml_rev_convert_signal_number(int signo); extern void raise_with_two_args(value tag, value arg1, value arg2) Noreturn; extern value* named_value_exn(const char* n); extern void* malloc_exn(size_t size); extern const char* string_ocaml_to_c(value s_v); extern const char* string_of_ocaml_string_option(value v); extern int int_of_ocaml_int_option(value v, int* i); extern const char** array_map(value array, const char* (*f__must_not_allocate)(value)); #endif /* OCAML_UTILS_H */ core-113.00.00/src/ocaml_utils_macros.h000066400000000000000000000013151256461075500175760ustar00rootroot00000000000000 #ifndef ocaml_utils_macros_h #define ocaml_utils_macros_h #include #define UNUSED __attribute__((unused)) #define Is_string(v) (Is_block(v) && Tag_val(v) == String_tag) #define Is_none(v) (Is_long(v) && Long_val(v) == 0) #define Is_some(v) (Is_block(v) && Tag_val(v) == 0 && Wosize_val(v) == 1) #define Is_int_option(v) (Is_none(v) || (Is_some(v) && Is_long(Field(v, 0)))) #define Is_string_option(v) (Is_none(v) || (Is_some(v) && Is_string(Field(v, 0)))) #define Is_custom(v) (Is_block(v) && Tag_val(v) == Custom_tag) #define Custom_block_name(v) (Custom_ops_val(v)->identifier) #define Is_custom_named(v, name) \ (Is_custom(v) && !strcmp_not_a_macro(name, Custom_block_name(v))) #endif core-113.00.00/src/ocaml_utils_stubs.c000066400000000000000000000050561256461075500174530ustar00rootroot00000000000000/* Various utility functions for C <-> Caml interoperability. */ #include int strcmp_not_a_macro(const char* s1, const char* s2) { /* See caml_utils_macros.h for why this is needed. */ return strcmp(s1, s2); } #include #include #include #include #include "ocaml_utils.h" #include "ocaml_utils_macros.h" /* Exceptions */ void raise_with_two_args(value tag, value arg1, value arg2) { value v_exc; Begin_roots3(tag, arg1, arg2); v_exc = caml_alloc_small(3, 0); Field(v_exc, 0) = tag; Field(v_exc, 1) = arg1; Field(v_exc, 2) = arg2; End_roots(); caml_raise(v_exc); } value* named_value_exn(const char* n) { value* v = caml_named_value(n); if (v == NULL) { char msg[256]; snprintf(msg, sizeof(msg), "%s not registered.", n); caml_failwith(msg); } return v; } void* malloc_exn(size_t size) { void* ptr; value* malloc_exn; ptr = malloc(size); if (ptr == NULL) { malloc_exn = named_value_exn("C_malloc_exn"); assert(malloc_exn != NULL); /* [named_value_exn] should ensure this. */ raise_with_two_args(*malloc_exn, Val_int(errno), Val_int(size)); } return ptr; } const char* string_ocaml_to_c(value s_v) { int length; char *s; assert(Is_string(s_v)); length = caml_string_length(s_v); s = malloc_exn(length + 1); memcpy(s, String_val(s_v), length + 1); return s; } const char* string_of_ocaml_string_option(value v) { assert(Is_string_option(v)); if (Is_none(v)) return NULL; return string_ocaml_to_c(Field(v, 0)); } int int_of_ocaml_int_option(value v, int* i) { assert(Is_int_option(v)); if (Is_some(v)) *i = Long_val(Field(v, 0)); return Is_none(v) ? 0 : 1; } const char** array_map(value array, const char* (*f__must_not_allocate_on_caml_heap)(value)) { const char** new_array; unsigned int i, length; length = Wosize_val(array); if (length == 0) return NULL; new_array = malloc_exn(sizeof(char*) * length); for (i = 0; i < length; i++) new_array[i] = f__must_not_allocate_on_caml_heap(Field(array, i)); return new_array; } CAMLprim value executing_bytecode (value *_vals, int *_nvals) { ((void)_vals); ((void)_nvals); return Val_true; } CAMLprim value not_executing_bytecode (value _v1, value _v2, value _v3, value _v4, value _v5, value _v6) { ((void)_v1); ((void)_v2); ((void)_v3); ((void)_v4); ((void)_v5); ((void)_v6); return Val_false; } CAMLprim value c_int_size (value _unit) { ((void)_unit); return Val_int(sizeof(int) * 8); } core-113.00.00/src/ofday.ml000066400000000000000000000333641256461075500152130ustar00rootroot00000000000000open Core_kernel.Std open Time_internal.Helpers (* Create an abstract type for Ofday to prevent us from confusing it with other floats. *) module Stable = struct module V1 = struct module T : sig type t = private float with bin_io include Comparable.S_common with type t := t include Comparable.With_zero with type t := t include Hashable_binable with type t := t include Robustly_comparable with type t := t include Stringable with type t := t include Floatable with type t := t val add : t -> Span.t -> t option val sub : t -> Span.t -> t option val diff : t -> t -> Span.t val of_span_since_start_of_day : Span.t -> t val to_span_since_start_of_day : t -> Span.t val start_of_day : t end = struct (* Number of seconds since midnight. *) include Float (* IF THIS REPRESENTATION EVER CHANGES, ENSURE THAT EITHER (1) all values serialize the same way in both representations, or (2) you add a new Time.Ofday version to stable.ml *) (* due to precision limitations in float we can't expect better than microsecond precision *) include Core_kernel.Float_robust_compare.Make (struct let robust_comparison_tolerance = 1E-6 end) let to_span_since_start_of_day t = Span.of_sec t (* ofday must be >= 0 and < 24h *) let is_valid (t:t) = let t = to_span_since_start_of_day t in Span.(<=) Span.zero t && Span.(<=) t Span.day ;; let of_span_since_start_of_day span = let module C = Float.Class in let s = Span.to_sec span in match Float.classify s with | C.Infinite -> invalid_arg "Ofday.of_span_since_start_of_day: infinite value" | C.Nan -> invalid_arg "Ofday.of_span_since_start_of_day: NaN value" | C.Normal | C.Subnormal | C.Zero -> if not (is_valid s) then invalid_argf "Ofday out of range: %f" s () else s ;; let start_of_day = 0. let add (t:t) (span:Span.t) = let t = t +. (Span.to_sec span) in if is_valid t then Some t else None let sub (t:t) (span:Span.t) = let t = t -. (Span.to_sec span) in if is_valid t then Some t else None let diff t1 t2 = Span.(-) (to_span_since_start_of_day t1) (to_span_since_start_of_day t2) end let create ?hr ?min ?sec ?ms ?us () = let sec, ms, us = match sec with | Some 60 -> Some 60, Some 0, Some 0 | _ -> sec, ms, us in T.of_span_since_start_of_day (Span.create ?hr ?min ?sec ?ms ?us ()) ;; TEST "create can handle a leap second" = let last_second = create ~hr:21 () in List.for_all ~f:(fun v -> v = last_second) [ create ~hr:20 ~min:59 ~sec:60 () ; create ~hr:20 ~min:59 ~sec:60 ~ms:500 () ; create ~hr:20 ~min:59 ~sec:60 ~ms:500 ~us:500 () ; create ~hr:20 ~min:59 ~sec:60 ~ms:0 ~us:500 () ] ;; let to_parts t = Span.to_parts (T.to_span_since_start_of_day t) let to_string_gen ~drop_ms ~drop_us ~trim x = assert (if drop_ms then drop_us else true); let module P = Span.Parts in let parts = to_parts x in let dont_print_us = drop_us || (trim && parts.P.us = 0) in let dont_print_ms = drop_ms || (trim && parts.P.ms = 0 && dont_print_us) in let dont_print_s = trim && parts.P.sec = 0 && dont_print_ms in let len = if dont_print_s then 5 else if dont_print_ms then 8 else if dont_print_us then 12 else 15 in let buf = String.create len in blit_string_of_int_2_digits buf ~pos:0 parts.P.hr; buf.[2] <- ':'; blit_string_of_int_2_digits buf ~pos:3 parts.P.min; if dont_print_s then () else begin buf.[5] <- ':'; blit_string_of_int_2_digits buf ~pos:6 parts.P.sec; if dont_print_ms then () else begin buf.[8] <- '.'; blit_string_of_int_3_digits buf ~pos:9 parts.P.ms; if dont_print_us then () else blit_string_of_int_3_digits buf ~pos:12 parts.P.us end end; buf ;; let to_string_trimmed t = to_string_gen ~drop_ms:false ~drop_us:false ~trim:true t let to_sec_string t = to_string_gen ~drop_ms:true ~drop_us:true ~trim:false t let to_millisec_string t = to_string_gen ~drop_ms:false ~drop_us:true ~trim:false t let of_string_iso8601_extended ?pos ?len str = let (pos, len) = match (Core_kernel.Ordered_collection_common.get_pos_len ?pos ?len ~length:(String.length str)) with | Result.Ok z -> z | Result.Error s -> failwithf "Ofday.of_string_iso8601_extended: %s" s () in try if len < 2 then failwith "len < 2" else begin let span = let hour = parse_two_digits str pos in if hour > 24 then failwith "hour > 24"; let span = Span.of_hr (float hour) in if len = 2 then span else if len < 5 then failwith "2 < len < 5" else if str.[pos + 2] <> ':' then failwith "first colon missing" else let minute = parse_two_digits str (pos + 3) in if minute >= 60 then failwith "minute > 60"; let span = Span.(+) span (Span.of_min (float minute)) in if hour = 24 && minute <> 0 then failwith "24 hours and non-zero minute"; if len = 5 then span else if len < 8 then failwith "5 < len < 8" else if str.[pos + 5] <> ':' then failwith "second colon missing" else let second = parse_two_digits str (pos + 6) in (* second can be 60 in the case of a leap second. Unfortunately, what with non-hour-multiple timezone offsets, we can't say anything about what the hour or minute must be in that case *) if second > 60 then failwithf "invalid second: %i" second (); if hour = 24 && second <> 0 then failwith "24 hours and non-zero seconds"; let seconds = Span.of_sec (float second) in if len = 8 then Span.(+) span seconds else if len = 9 then failwith "length = 9" else match str.[pos + 8] with | '.' | ',' -> let last = pos + len - 1 in let rec loop pos subs = let subs = subs * 10 + Char.get_digit_exn str.[pos] in if pos = last then subs else loop (pos + 1) subs in let subs = loop (pos + 9) 0 in if hour = 24 && subs <> 0 then failwith "24 hours and non-zero subseconds"; let seconds = Span.(+) seconds (Span.of_sec (float subs /. (10. ** float (len - 9)))) in (* above we test for a leap second, but we can't represent the leap second within an Ofday.t, so here we are forced to trim it back if we have more than 60 seconds. *) let seconds = if Span.(>) seconds (Span.of_sec 60.) then Span.of_sec 60. else seconds in Span.(+) span seconds | _ -> failwith "missing subsecond separator" in T.of_span_since_start_of_day span end with exn -> invalid_argf "Ofday.of_string_iso8601_extended(%s): %s" (String.sub str ~pos ~len) (Exn.to_string exn) () ;; TEST "of_string_iso8601_extended supports leap seconds" = let last_second = create ~hr:21 () in List.for_all ~f:(fun s -> of_string_iso8601_extended s = last_second) [ "20:59:60" ; "20:59:60.500" ; "20:59:60.000" ] ;; TEST "of_string_iso8601_extended doesn't support two leap seconds" = Exn.does_raise (fun () -> of_string_iso8601_extended "23:59:61") let small_diff = let hour = 3600. in (fun ofday1 ofday2 -> let ofday1 = Span.to_sec (T.to_span_since_start_of_day ofday1) in let ofday2 = Span.to_sec (T.to_span_since_start_of_day ofday2) in let diff = ofday1 -. ofday2 in (* d1 is in (-hour; hour) *) let d1 = Float.mod_float diff hour in (* d2 is in (0;hour) *) let d2 = Float.mod_float (d1 +. hour) hour in let d = if d2 > hour /. 2. then d2 -. hour else d2 in Span.of_sec d) ;; (* There are a number of things that would be shadowed by this include because of the scope of Constrained_float. These need to be defined below. It's a an unfortunate situation because we would like to say include T, without shadowing. *) include T let to_string t = to_string_gen ~drop_ms:false ~drop_us:false ~trim:false t include Pretty_printer.Register (struct type nonrec t = t let to_string = to_string let module_name = "Core.Std.Time.Ofday" end) let of_string s = try let h, m, s = match String.split s ~on:':' with | [h; m; s] -> (h, m, Float.of_string s) | [h; m] -> (h, m, 0.) | [hm] -> if Int.(=) (String.length hm) 4 then ((String.sub hm ~pos:0 ~len:2), (String.sub hm ~pos:2 ~len:2), 0.) else failwith "No colon, expected string of length four" | _ -> failwith "More than two colons" in let h = Int.of_string h in let m = Int.of_string m in let is_end_of_day = Int.(h = 24 && m = 0) && Float.(s = 0.) in if not (Int.(h <= 23 && h >= 0) || is_end_of_day) then failwithf "hour out of valid range: %i" h (); if not Int.(m <= 59 && m >= 0) then failwithf "minutes out of valid range: %i" m (); let s = if Float.(0. <= s && s < 60.) then s else if Float.(s < 61.) (* allow a leap second *) then 60. else failwithf "seconds out of valid range: %g" s (); in (* create takes integer arguments for each field, and so we have to use add to get float seconds onto the value. *) Option.value_exn (add (create ~hr:h ~min:m ()) (Span.of_sec s)) with exn -> invalid_argf "Ofday.of_string (%s): %s" s (Exn.to_string exn) () ;; TEST "of_string supports leap seconds" = let last_second = create ~hr:21 () in List.for_all ~f:(fun s -> of_string s = last_second) [ "20:59:60" ; "20:59:60.500" ; "20:59:60.000" ] ;; let t_of_sexp sexp = match sexp with | Sexp.Atom s -> begin try of_string s with | Invalid_argument s -> of_sexp_error ("Ofday.t_of_sexp: " ^ s) sexp end | _ -> of_sexp_error "Ofday.t_of_sexp" sexp ;; let sexp_of_t span = Sexp.Atom (to_string span) let of_float f = T.of_span_since_start_of_day (Span.of_sec f) end end include Stable.V1 module C = struct type t = T.t with bin_io type comparator_witness = T.comparator_witness let comparator = T.comparator (* In 108.06a and earlier, ofdays in sexps of Maps and Sets were raw floats. From 108.07 through 109.13, the output format remained raw as before, but both the raw and pretty format were accepted as input. From 109.14 on, the output format was changed from raw to pretty, while continuing to accept both formats. Once we believe most programs are beyond 109.14, we will switch the input format to no longer accept raw. *) let sexp_of_t = sexp_of_t let t_of_sexp sexp = match Option.try_with (fun () -> T.of_float (Float.t_of_sexp sexp)) with | Some t -> t | None -> t_of_sexp sexp ;; end module Map = Map.Make_binable_using_comparator (C) module Set = Set.Make_binable_using_comparator (C) TEST = Set.equal (Set.of_list [start_of_day]) (Set.t_of_sexp (Sexp.List [Float.sexp_of_t (to_float start_of_day)])) ;; module Zoned = struct module Stable = struct module V1 = struct module T = struct type ofday = t type t = { ofday : Stable.V1.t; zone : Zone.Stable.V1.t; } with bin_io, fields, compare type sexp_repr = Stable.V1.t * Zone.Stable.V1.t with sexp let sexp_of_t t = <:sexp_of< sexp_repr >> (t.ofday, t.zone) let t_of_sexp sexp = let (ofday, zone) = <:of_sexp< sexp_repr >> sexp in { ofday; zone; } ;; let hash t = Hashtbl.hash t end include T include Comparable.Make_binable(T) include Core_kernel.Hashable.Make_binable(T) end end include Stable.V1 let create ofday zone = { ofday; zone } let create_local ofday = create ofday Zone.local let of_string string : t = match String.split string ~on:' ' with | [ ofday; zone ] -> { ofday = of_string ofday; zone = Zone.of_string zone; } | _ -> failwithf "Ofday.Zoned.of_string %s" string () ;; let to_string (t : t) : string = String.concat [ to_string t.ofday; " "; Zone.to_string t.zone ] ;; include Pretty_printer.Register (struct type nonrec t = t let to_string = to_string let module_name = "Core.Std.Time.Ofday.Zoned" end) TEST_UNIT = List.iter [ "12:00 nyc"; "12:00 America/New_York"; ] ~f:(fun string -> let t = of_string string in assert (t = of_string (to_string t)); assert (t = t_of_sexp (sexp_of_t t))) ;; end core-113.00.00/src/ofday.mli000066400000000000000000000054231256461075500153570ustar00rootroot00000000000000open Core_kernel.Std (* Represented as a number of seconds since midnight *) type t = private float with bin_io, sexp module Zoned : sig (** A time of day along with a time zone. Expresses things like "Seinfeld moved to 6:30pm EST.", while a plain [Ofday] expresses something more like "I eat lunch at noon (in whichever timezone I'm in at the time).". *) (** Sexps look like "(12:01 nyc)" Two [t]'s may or may not correspond to the same times depending on which date they're evaluated. *) type ofday = t type t with bin_io, sexp (** Strings look like "12:01 nyc" *) include Stringable with type t := t include Comparable_binable with type t := t include Hashable_binable with type t := t include Pretty_printer.S with type t := t val create : ofday -> Zone.t -> t val create_local : ofday -> t val ofday : t -> ofday val zone : t -> Zone.t module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io end end end include Comparable_binable with type t := t include Comparable.With_zero with type t := t include Floatable with type t := t include Hashable_binable with type t := t include Pretty_printer.S with type t := t include Robustly_comparable with type t := t include Stringable with type t := t val create : ?hr:int -> ?min:int -> ?sec:int -> ?ms:int -> ?us:int -> unit -> t val to_parts : t -> Span.Parts.t (** Smallest valid ofday. There is no exposed end_of_day value because the upper end of the range is not closed. *) val start_of_day : t val to_span_since_start_of_day : t -> Span.t val of_span_since_start_of_day : Span.t -> t (* Due to a circular reference, this function is defined in Core.Std. *) (* val now : unit -> t *) (** [add t s] shifts the time of day [t] by the span [s]. It returns None if the result is not in the same day. *) val add : t -> Span.t -> t option val sub : t -> Span.t -> t option (** [diff t1 t2] returns the difference in time between two ofdays, as if they occurred on the same day *) val diff : t -> t -> Span.t (* Returns the time-span separating the two of-days, ignoring the hour information, and assuming that the of-days represent times that are within a half-hour of each other. This is useful for comparing two ofdays in unknown time-zones. *) val small_diff : t -> t -> Span.t (** trailing seconds and subseconds are trimmed off if they are 0 *) val to_string_trimmed : t -> string (** trailing milliseconds are trimmed *) val to_sec_string : t -> string val of_string_iso8601_extended : ?pos:int -> ?len:int -> string -> t (** with milliseconds *) val to_millisec_string : t -> string module Stable : sig module V1 : sig type nonrec t = t with bin_io, compare, sexp end end core-113.00.00/src/only_in_test.ml000066400000000000000000000000411256461075500166010ustar00rootroot00000000000000include Core_kernel.Only_in_test core-113.00.00/src/option.ml000066400000000000000000000000331256461075500154040ustar00rootroot00000000000000include Core_kernel.Option core-113.00.00/src/or_error.ml000066400000000000000000000000351256461075500157270ustar00rootroot00000000000000include Core_kernel.Or_error core-113.00.00/src/ordered_collection_common.ml000066400000000000000000000000561256461075500213100ustar00rootroot00000000000000include Core_kernel.Ordered_collection_common core-113.00.00/src/ordering.ml000066400000000000000000000000351256461075500157070ustar00rootroot00000000000000include Core_kernel.Ordering core-113.00.00/src/out_channel.ml000066400000000000000000000000401256461075500163710ustar00rootroot00000000000000include Core_kernel.Out_channel core-113.00.00/src/pid.ml000066400000000000000000000000301256461075500146450ustar00rootroot00000000000000include Core_kernel.Pid core-113.00.00/src/piecewise_linear.ml000066400000000000000000000705071256461075500174200ustar00rootroot00000000000000open Core_kernel.Std open Int.Replace_polymorphic_compare open Piecewise_linear_intf module Common = struct (** Like [Array.is_sorted], but requires strictness if [strict] is true. *) (* Checks array is in (possibly strictly) ascending order per compare function *) let array_is_sorted ~strict a ~compare = let test = if strict then fun x1 x2 -> compare x1 x2 < 0 else fun x1 x2 -> compare x1 x2 <= 0 in let len = Array.length a in let rec loop i = if i >= len - 1 then true else test a.(i) a.(i + 1) && loop (i + 1) in loop 0 (** [array_is_strongly_finite a] checks that [a] is "strongly finite": in addition to requiring each individual element to be finite, we require that differences of consecutive elements are finite. This last condition is only relevant in corner cases like [a.(0) = -1e308, a.(1) = 1e308], which will have [a.(1) -. a.(0) = infinity], even though the elements themselves are finite. The motivation for strong finiteness is that, if it fails, we can run into trouble with linear interpolation on the corresponding interval. Rather than [bool], the return type is [(unit, string) Result.t] for the sake of more informative error messages. [Ok ()] is returned when the array is strongly finite, and [Error error_message] is returned if it is not strongly finite. *) let array_is_strongly_finite a = match Array.findi a ~f:(fun _ x -> not (Float.is_finite x)) with | Some (index, x) -> Error (sprintf "at index %i, had non-finite value %g" index x) | None -> let len = Array.length a in let rec loop i = if i >= len - 1 then Ok () else if Float.is_finite (a.(i+1) -. a.(i)) then loop (i + 1) else Error (sprintf "at indices %i, %i, had non-finite difference \ %g -. %g = %g" i (i + 1) a.(i+1) a.(i) (a.(i+1) -. a.(i))) in loop 0 TEST_MODULE = struct let a = [|0.; 0.1; 0.2; 0.3; 0.4; 0.5; 0.6; 0.7; 0.8|];; let b = [|0.; 0.1; 0.2; 0.4; 0.4; 0.4; 0.6; 0.7|];; let c = [|0.; 0.5; 0.4; 0.6|] (* an array that is not sorted *) TEST = array_is_sorted ~strict:false a ~compare:Float.compare TEST = array_is_sorted ~strict:true a ~compare:Float.compare TEST = array_is_sorted ~strict:false b ~compare:Float.compare TEST = not (array_is_sorted ~strict:true b ~compare:Float.compare) TEST = not (array_is_sorted ~strict:false c ~compare:Float.compare) TEST = not (array_is_sorted ~strict:true c ~compare:Float.compare) let not_strongly_finite1 = [| (-1e308); 1e308 |] let not_strongly_finite2 = [| 1.; 2.; Float.nan |] let not_strongly_finite3 = [| Float.infinity |] TEST = Result.is_error (array_is_strongly_finite not_strongly_finite1) TEST = Result.is_error (array_is_strongly_finite not_strongly_finite2) TEST = Result.is_error (array_is_strongly_finite not_strongly_finite3) end end module Stable = struct module V1 = struct module Impl : sig type t with compare (** If [strict] is [true], the x-values must be strictly increasing. *) val create : strict:bool -> (float * float) list -> t Or_error.t val first_knot : t -> (float * float) option val last_knot : t -> (float * float) option val to_knots : t -> (float * float) list (** Data is not copied *) val to_knots' : t -> float array * float array (** Data is not copied or validated. *) val of_knots' : x:float array -> y:float array -> t (** Return the inverse of t. Requires strict monotonicity of y-values. Does not check x-values. *) val invert : t -> t Or_error.t val get : t -> float -> float (* ?force is used to allow us to run bench tests. *) val precache : ?force:bool -> ?density:float -> t -> unit val create_from_linear_combination : (t * float) list -> t Or_error.t end = struct module Lookup = struct type t = { indices : int array ; scale : float } let cached_bounds { indices ; scale } t_x x = (* We're guaranteed that nl>=1, although the logic actually works when nl=0 *) let nl = Array.length indices in (* Note that we only index the interior points. *) let idx = Pervasives.int_of_float ((x -. t_x.(0)) *. scale) in let m = if idx = 0 then 0 else indices.(idx-1) in let n = if idx = nl then (Array.length t_x) - 1 else indices.(idx)+1 in m,n end (* float arrays don't have the boxing overhead that (float * float) arrays have. Also, when inverting, we can often swap x and y without duplicating the floats. *) type t = { x : float array (* the x coordinates of the knots *) ; y : float array (* the corresponding y coordinates of the knots *) (* lookup.(i) is the index of the knot immmediately prior to the ith equi-spaced interior point in the interval x.(0), x.(end-1) *) ; mutable lookup : Lookup.t option } let compare t1 t2 = <:compare< float array * float array >> (t1.x, t1.y) (t2.x, t2.y) (** [validate ~strict t] returns [Ok t] if [t] is valid, and an [Error] otherwise. *) let validate ~strict t = let { x; y; _ } = t in let len_x = Array.length x in let len_y = Array.length y in if len_x <> len_y then Or_error.errorf "length x = %i <> length y = %i" len_x len_y else if len_x = 0 then Or_error.error_string "no knots given" else match Common.array_is_strongly_finite y with | Error error_message -> error "problem with knot values" error_message <:sexp_of> | Ok () -> match Common.array_is_strongly_finite x with | Error error_message -> error "problem with knot keys" error_message <:sexp_of> | Ok () -> if Common.array_is_sorted ~strict ~compare:Float.compare x then Ok t else Or_error.error_string (if strict then "knot keys are not strictly increasing" else "knot keys are unsorted") let create ~strict knots = let x = Array.of_list_map knots ~f:fst in let y = Array.of_list_map knots ~f:snd in let tentative_result = { x; y; lookup = None } in validate ~strict tentative_result let first_knot t = if Array.length t.x > 0 then Some (t.x.(0), t.y.(0)) else None let last_knot t = let len = Array.length t.x in if len > 0 then Some (t.x.(len-1), t.y.(len-1)) else None let to_knots t = (* [validate] above checks that [t.x] and [t.y] have the same length. *) Array.map2_exn t.x t.y ~f:(fun x y -> (x,y)) |! Array.to_list (* Note that while we are not copying t.x and t.y here, they are not returned directly to the user. Rather, they will get passed to Array.map in Make(...).to_knots'. *) let to_knots' t = (t.x, t.y) let of_knots' ~x ~y = { x; y; lookup = None} let invert t = (* We try swapping x and y and validating *) let lookup = None in match validate ~strict:true { x = t.y; y = t.x; lookup } with | Ok _ as result -> result | Error error_when_same_order -> (* Try reversing them; i.e. [invert t] should work if t.y is either strictly increasing or strictly decreasing *) let x = Array.copy t.y in Array.rev_inplace x; let y = Array.copy t.x in Array.rev_inplace y; match validate ~strict:true { x; y; lookup } with | Ok _ as result -> result | Error error_when_reversed -> Or_error.error "Swapping x and y failed, for both original and reversed order" (`Same_order error_when_same_order, `Reverse_order error_when_reversed) <:sexp_of<[`Same_order of Error.t] * [`Reverse_order of Error.t]>> (* ?force is used to allow us to run bench tests. *) let precache ?(force = false) ?(density = 1.) t = let t_x = t.x in let m = Array.length t_x in let n = Float.to_int (float m *. density) - 2 in if force || n > Option.value_map t.lookup ~default:0 ~f:(fun { indices; _ } -> Array.length indices ) then begin let j = ref 0 in let width = t_x.(m-1) -. t_x.(0) in let scale = float (n + 1) /. width in let indices = Array.init n ~f:(fun i -> let rec loop () = let idx = Float.to_int ((t_x.(!j+1) -. t_x.(0)) *. scale) in if idx < i+1 then (incr j; loop () ) in loop (); (* j is the highest index of a knot whose associated value of idx is < i+1 *) !j ) in t.lookup <- Some { indices ; scale } end let linear ~x ~x1 ~y1 ~x2 ~y2 = let weight = (x -. x1) /. (x2 -. x1) in (* note: numerically unstable if x2=.x1 *) (* A note about [weight]: [linear] is only called with [x1 <= x < x2], and [x2 -. x1] finite. Even with float issues, this should yield the following guarantees: 0. <= x -. x1 <= x2 -. x1 < infinity, 0. < x2 -. x1 (As annoying as denormals are, they do lead to the desirable property that x1 < x2 implies 0. < x2 -. x1.) So, we should get 0. <= weight <= 1. *) assert (Float.(<=) 0. weight && Float.(<=) weight 1.); y1 +. weight *. (y2 -. y1) let get t x = if Float.is_nan x then invalid_arg "Piecewise_linear.get on nan"; let t_x = t.x in let t_y = t.y in let l = Array.length t_x in let t_x0 = t_x.(0) in (* Using Float.(<=) on next line gives wrong semantics if t starts with a discontinuity. *) if Float.(<) x t_x0 then t_y.(0) else if Float.(<=) t_x.(l - 1) x then t_y.(l - 1) else (* Using the cached lookup, if available, determine a pair of knots that lie either side of x *) let m,n = match t.lookup with | None -> 0,l-1 | Some lookup -> Lookup.cached_bounds lookup t_x x in (* Writing this with a recursive function incurs an overhead that means that using a while loop is up to 10% quicker. *) let m = ref m in let n = ref n in (* loop invariant: t_x.(m) <= x < t_x.(n) *) while !n - !m > 1 do let mid = (!m + !n) / 2 in if Float.(<=) (Array.unsafe_get t_x mid) x then m := mid else n := mid done; let i = !m in linear ~x ~x1:t_x.(i) ~y1:t_y.(i) ~x2:t_x.(i+1) ~y2:t_y.(i+1) let create_from_linear_combination with_weights = match with_weights with | [] -> Or_error.error_string "Piecewise_linear.create_from_linear_combination with empty list" | with_weights -> let xs_strictly_incr = List.for_all with_weights ~f:(fun (t, _) -> Common.array_is_sorted ~strict:true t.x ~compare:Float.compare) in if not xs_strictly_incr then Or_error.error_string "Knot keys are not strictly increasing. create_from_linear_combination \ does not support discontinuities" else let weights_are_ordinary = List.for_all with_weights ~f:(fun (_, w) -> Float.is_finite w) in if not weights_are_ordinary then Or_error.error_string "Some weights are not finite" else let xs = List.map with_weights ~f:(fun (t, _) -> Float.Set.of_sorted_array_unchecked t.x ) |> Float.Set.union_list in let y_of_x x = List.fold with_weights ~init:0. ~f:(fun y_accum (t, weight) -> y_accum +. (get t x) *. weight) in create (List.map (Set.to_list xs) ~f:(fun x -> x, y_of_x x)) ~strict:true end type ('key, 'value) t_ = Impl.t module type S = S with type ('k, 'v) t_ := ('k, 'v) t_ module Make (Key : Float_like) (Value : Float_like) = struct type key = Key.t type value = Value.t module T = struct type t = Impl.t with compare let create knots = let float_knots = List.map knots ~f:(fun (x, y) -> (Key.to_float x, Value.to_float y)) in Impl.create ~strict:false float_knots type knots = (Key.t * Value.t) list with sexp let convert_tuple (x, y) = Key.of_float x, Value.of_float y let first_knot t = Option.map (Impl.first_knot t) ~f:convert_tuple let last_knot t = Option.map (Impl.last_knot t) ~f:convert_tuple let to_knots t = List.map (Impl.to_knots t) ~f:(fun (x, y) -> (Key.of_float x, Value.of_float y)) let to_knots' t = let (x, y) = Impl.to_knots' t in (Array.map x ~f:Key.of_float, Array.map y ~f:Value.of_float) let t_of_sexp sexp = let knots = knots_of_sexp sexp in match create knots with | Error error -> Sexplib.Conv.of_sexp_error (Error.to_string_hum error) sexp | Ok t -> t let sexp_of_t t = sexp_of_knots (to_knots t) let create_from_linear_combination = Impl.create_from_linear_combination end include T (* We convert back to Key.t and Value.t for bin_io, because, for example, Time.Stable.V1 has bin_io, but there is no guarantee that Time.to_float and Time.of_float will not have their semantics change. So, the user who goes to the trouble of creating inputs K and V to Make with stable bin_io will be assured that Make(K)(V).Stable.V1.t has stable bin_io. *) module Bin_rep = struct type t = { x : Key.t array ; y : Value.t array } with bin_io end include Binable.Of_binable (Bin_rep) (struct type nonrec t = t let to_binable t = let (x, y) = to_knots' t in { Bin_rep. x; y } let of_binable (bt : Bin_rep.t) = let x = Array.map bt.x ~f:Key.to_float in let y = Array.map bt.y ~f:Value.to_float in Impl.of_knots' ~x ~y end) let precache = Impl.precache ~force:false let get t x = Value.of_float (Impl.get t (Key.to_float x)) end type invertible = { regular : Impl.t ; inverse : Impl.t } with compare type ('key, 'value) t_invertible = invertible module type S_invertible = S_invertible with type ('k, 'v) t_ := ('k, 'v) t_invertible module Make_invertible (Key : Float_like) (Value : Float_like) = struct module M = Make (Key) (Value) type key = Key.t type value = Value.t module T = struct type t = invertible with compare let sexp_of_t t = M.sexp_of_t t.regular let t_of_sexp sexp = let regular = M.t_of_sexp sexp in match Impl.invert regular with | Ok inverse -> { regular; inverse } | Error error -> Sexplib.Conv.of_sexp_error (Error.to_string_hum error) sexp end include T (* Our bin_io only stores [regular], and reconstructs [inverse] when loading. *) include Binable.Of_binable (M) (struct type nonrec t = t let to_binable t = t.regular let of_binable regular = let inverse = Or_error.tag (Impl.invert regular) "Got non-invertible set of knots when deserializing?" |> Or_error.ok_exn in { regular; inverse } end) let create_from_regular regular = let open Result.Monad_infix in Impl.invert regular >>| fun inverse -> { regular; inverse } let create knots = let open Result.Monad_infix in let float_knots = List.map knots ~f:(fun (x, y) -> (Key.to_float x, Value.to_float y)) in Impl.create ~strict:true float_knots >>= create_from_regular let get t = M.get t.regular let first_knot t = M.first_knot t.regular let last_knot t = M.last_knot t.regular let to_knots t = M.to_knots t.regular let to_knots' t = M.to_knots' t.regular let get_inverse t y = Key.of_float (Impl.get t.inverse (Value.to_float y)) let precache ?density {regular; inverse} = Impl.precache ?density regular; Impl.precache ?density inverse let create_from_linear_combination with_weights = let open Result.Monad_infix in let with_weights = List.map with_weights ~f:(fun (t, w) -> t.regular, w) in Impl.create_from_linear_combination with_weights >>= create_from_regular end end end include Stable.V1 module F = Float module Time_ = Time (* so we can refer to it later *) module Time = Make (Time) (F) module Ofday = Make (Ofday) (F) module Span = Make (Span) (F) module Float = Make (Float) (F) module Int = Make (Int) (F) TEST_MODULE = struct let expected name expected actual = if F.(<>) expected actual then failwithf "in %s: expected %.2f, actual %.2f" name expected actual () let expected_tol ~tol name expected actual = if F.(>) (F.abs (expected -. actual)) tol then failwithf "in %s: expected %.15g, actual %.15g" name expected actual () let to_knots x_values = List.map x_values ~f:(fun x -> (x, 0.)) let bad_knots = to_knots [1.; 0.; 2.] TEST_MODULE "normal" = struct TEST = Result.is_ok (Float.create (to_knots [1.; 1.; 2.])) TEST = Result.is_error (Float.create bad_knots) TEST_UNIT = (* Test the normal case *) let knots = [(1., 1.); (1.1, 1.5); (2., 2.)] in let t = Or_error.ok_exn (Float.create knots) in expected "get" 1. (Float.get t 1.); expected "get" 1.5 (Float.get t 1.1); expected "get" 1.25 (Float.get t 1.05); expected "get" 1. (Float.get t 0.9); expected "get" 2. (Float.get t 2.5); expected "get" 2. (Float.get t 2.) TEST_UNIT = (* Test the normal case with repeated x-values in knots *) let knots = [(0.1, 2.); (0.5, 4.); (0.5, 5.); (0.9, 1.); (2.2, 2.2)] in let t = Or_error.ok_exn (Float.create knots) in expected "get" 5. (Float.get t 0.5); (* right continuity *) expected "get" 4. (Float.get t 0.6); expected "get" 3.5 (Float.get t 0.4); expected_tol ~tol:1e-12 "get" (4. -. 5e-7) (Float.get t (0.5 -. 1e-7)) TEST_UNIT = (* Test a degenerate case *) let knots = [(1., 2.)] in let t = Or_error.ok_exn (Float.create knots) in expected "get" 2. (Float.get t 0.5); expected "get" 2. (Float.get t 1.); expected "get" 2. (Float.get t 1.5) TEST_UNIT = let with_weights = [ Or_error.ok_exn (Float.create [(1., 1.); (1.1, 1.5); (2., 2.)]), 1. ; Or_error.ok_exn (Float.create [(1., 1.); (1.1, 1.5); (2., 3.)]), 1. ] in let t = Or_error.ok_exn (Float.create_from_linear_combination with_weights) in expected "get" 2. (Float.get t 1.); expected "get" 2.5 (Float.get t 1.05); expected "get" 5. (Float.get t 5.) end TEST_MODULE "precached" = struct TEST = Result.is_ok (Float.create (to_knots [1.; 1.; 2.])) TEST = Result.is_error (Float.create bad_knots) TEST_UNIT = (* Test the normal case *) let knots = [(1., 1.); (1.1, 1.5); (2., 2.)] in let t = Or_error.ok_exn (Float.create knots) in Float.precache t; expected "get" 1. (Float.get t 1.); expected "get" 1.5 (Float.get t 1.1); expected "get" 1.25 (Float.get t 1.05); expected "get" 1. (Float.get t 0.9); expected "get" 2. (Float.get t 2.5); expected "get" 2. (Float.get t 2.) TEST_UNIT = (* Test the normal case with repeated x-values in knots *) let knots = [(0.1, 2.); (0.5, 4.); (0.5, 5.); (0.9, 1.); (2.2, 2.2)] in let t = Or_error.ok_exn (Float.create knots) in Float.precache t; expected "get" 5. (Float.get t 0.5); (* right continuity *) expected "get" 4. (Float.get t 0.6); expected "get" 3.5 (Float.get t 0.4); expected_tol ~tol:1e-12 "get" (4. -. 5e-7) (Float.get t (0.5 -. 1e-7)) TEST_UNIT = (* Test a degenerate case *) let knots = [(1., 2.)] in let t = Or_error.ok_exn (Float.create knots) in Float.precache t; expected "get" 2. (Float.get t 0.5); expected "get" 2. (Float.get t 1.); expected "get" 2. (Float.get t 1.5) (* This test exposed a floating point error when we weren't populating the cached lookup correctly *) TEST_UNIT = let x0 = -0.18064178089785571 in let x1 = 0.05702505363595689 in let x2 = 0.373914166347706967 in let knots = [(x0, 0.); (x1, 0.); (x1, 1.); (x2, 1.)] in let t = Or_error.ok_exn (Float.create knots) in Float.precache ~density:2. t; let just_below_x1 = 0.0570250536359568835 in (* Check that this value really is less than x1: *) if F.(>=) just_below_x1 x1 then failwith "Bug in test, not necessarily in module"; let result = Float.get t just_below_x1 in expected "get" 0. result end TEST_MODULE "invertible" = struct module Float_invertible = Make_invertible (F) (F) let not_invertible = [(1., 1.); (1., 1.5); (2., 2.)] let not_invertible2 = [(1., 1.); (1.5, 1.); (2., 2.)] TEST = Result.is_error (Float_invertible.create not_invertible) TEST = Result.is_error (Float_invertible.create not_invertible2) TEST = Result.is_error (Float_invertible.create bad_knots) let check_both t x y = expected "get" y (Float_invertible.get t x); expected "get_inverse" x (Float_invertible.get_inverse t y) TEST_UNIT = (* Test the case where both x and y are increasing *) let is_invertible = [(1., 1.); (1.1, 1.5); (2., 2.)] in let t = Or_error.ok_exn (Float_invertible.create is_invertible) in check_both t 1. 1.; check_both t 1.1 1.5; check_both t 1.05 1.25; (* Some values before first knot, after last knot *) expected "get" 1. (Float_invertible.get t 0.5); expected "get" 2. (Float_invertible.get t 2.5); expected "get_inverse" 1. (Float_invertible.get_inverse t 0.5); expected "get_inverse" 2. (Float_invertible.get_inverse t 2.5) TEST_UNIT = (* Test the case where y is decreasing *) let is_invertible = [(1., 2.); (1.1, 1.5); (2., 1.)] in let t = Or_error.ok_exn (Float_invertible.create is_invertible) in check_both t 1. 2.; check_both t 1.1 1.5; check_both t 1.05 1.75; (* Some values before first knot, after last knot *) expected "get" 2. (Float_invertible.get t 0.5); expected "get" 1. (Float_invertible.get t 2.5); expected "get_inverse" 2. (Float_invertible.get_inverse t 0.5); expected "get_inverse" 1. (Float_invertible.get_inverse t 2.5) end TEST_MODULE "io" = struct (* The following tests want exact equality, so they could fail if sexp conversion or binary io is inexact. However, we have used values that should be preserved exactly. *) open Bigarray let t0 = Time_.of_string "2014-05-20 12:34:56-04:00" let t1 = Time_.of_string "2014-05-20 15:00:00-04:00" let t2 = Time_.of_string "2014-05-20 16:00:00-04:00" TEST "sexp" = let knots = [(t0, 2.); (t1, 1.5); (t2, 1.)] in let t = Or_error.ok_exn (Time.create knots) in let sexp = Time.sexp_of_t t in let t' = Time.t_of_sexp sexp in Time.compare t t' = 0 (* The following type annotation is included so that if, say, buf changes to fortran_layout--not that we expect that--then the code will no longer compile. *) let buf_append buf0 buf1 : (char, int8_unsigned_elt, c_layout) Array1.t = let len0 = Array1.dim buf0 in let len1 = Array1.dim buf1 in let result = Bin_prot.Common.create_buf (len0 + len1) in Bin_prot.Common.blit_buf ~src_pos:0 ~src:buf0 ~dst_pos:0 ~dst:result len0; Bin_prot.Common.blit_buf ~src_pos:0 ~src:buf1 ~dst_pos:len0 ~dst:result len1; result let reader_of_buf src = let current_offset = ref 0 in fun dst ~pos ~len -> begin Bin_prot.Common.blit_buf ~src_pos:!current_offset ~src ~dst_pos:pos ~dst len; current_offset := !current_offset + len end TEST "bin_io" = let knots0 = [(t0, 2.); (t1, 1.5); (t2, 1.)] in let knots1 = [(t0, 0.5); (t1, 3.); (t2, 3.5)] in let t0 = Or_error.ok_exn (Time.create knots0) in let buf0 = Bin_prot.Utils.bin_dump ~header:true Time.bin_writer_t t0 in let t1 = Or_error.ok_exn (Time.create knots1) in let buf1 = Bin_prot.Utils.bin_dump ~header:true Time.bin_writer_t t1 in let buf = buf_append buf0 buf1 in let read = reader_of_buf buf in let t0' = Bin_prot.Utils.bin_read_stream ~read Time.bin_reader_t in let t1' = Bin_prot.Utils.bin_read_stream ~read Time.bin_reader_t in Time.compare t0 t0' = 0 && Time.compare t1 t1' = 0 && Time.compare t0 t1 <> 0 module Time_invertible = Make_invertible (Time_) (F) TEST "invertible sexp" = let knots = [(t0, 2.); (t1, 1.5); (t2, 1.)] in let t = Or_error.ok_exn (Time_invertible.create knots) in let sexp = Time_invertible.sexp_of_t t in let t' = Time_invertible.t_of_sexp sexp in Time_invertible.compare t t' = 0 TEST "invertible bin_io" = let knots0 = [(t0, 2.); (t1, 1.5); (t2, 1.)] in let knots1 = [(t0, 0.5); (t1, 3.); (t2, 3.5)] in let t0 = Or_error.ok_exn (Time_invertible.create knots0) in let buf0 = Bin_prot.Utils.bin_dump ~header:true Time_invertible.bin_writer_t t0 in let t1 = Or_error.ok_exn (Time_invertible.create knots1) in let buf1 = Bin_prot.Utils.bin_dump ~header:true Time_invertible.bin_writer_t t1 in let buf = buf_append buf0 buf1 in let read = reader_of_buf buf in let t0' = Bin_prot.Utils.bin_read_stream ~read Time_invertible.bin_reader_t in let t1' = Bin_prot.Utils.bin_read_stream ~read Time_invertible.bin_reader_t in Time_invertible.compare t0 t0' = 0 && Time_invertible.compare t1 t1' = 0 && Time_invertible.compare t0 t1 <> 0 end end BENCH_MODULE "Piecewise_linear tests" = struct let num_knots = [2; 100; 10_000] let create_knots len = let a = -2.1 in let b = 2.1 in (* x is linearly spaced from a to b and y = x ** 3. *) let dx = (b -. a) /. (F.of_int len -. 1.) in Array.init len ~f:(fun i -> let x = a +. F.of_int i *. dx in (x, x *. x *. x) ) |> Array.to_list (* Some x values can yield faster lookups than others, so we explore the domain a little in the benchmarks by leting x' = x ** 2 - 2. This bounces around in the interval [-2, 2]. *) BENCH_INDEXED "get" len num_knots = let t = Or_error.ok_exn (Float.create (create_knots len)) in let x = ref 0.3 in (fun () -> let x' = !x in let x' = x' *. x' -. 2. in x := x'; ignore (Float.get t x')) module FI = Make_invertible (F) (F) (* This can actually be a little faster than the above, but note that the knots are different. *) BENCH_INDEXED "get_inverse" len num_knots = let t = Or_error.ok_exn (FI.create (create_knots len)) in let x = ref 0.3 in (fun () -> let x' = !x in let x' = x' *. x' -. 2. in x := x'; ignore (FI.get_inverse t x')) BENCH_FUN "testing overhead" = let x = ref 0.3 in (fun () -> let x' = !x in let x' = x' *. x' -. 2. in x := x') let density = Some 1.5 BENCH_INDEXED "precache" len num_knots = let t = Or_error.ok_exn (Float.create (create_knots len)) in (fun () -> ignore (Stable.V1.Impl.precache ~force:true ?density t)) BENCH_INDEXED "precache then get" len num_knots = let t = Or_error.ok_exn (Float.create (create_knots len)) in Float.precache t ?density; let x = ref 0.3 in (fun () -> let x' = !x in let x' = x' *. x' -. 2. in x := x'; ignore (Float.get t x')) BENCH_INDEXED "precache then get_inverse" len num_knots = let t = Or_error.ok_exn (FI.create (create_knots len)) in FI.precache t ?density; let x = ref 0.3 in (fun () -> let x' = !x in let x' = x' *. x' -. 2. in x := x'; ignore (FI.get_inverse t x')) end core-113.00.00/src/piecewise_linear.mli000066400000000000000000000032361256461075500175640ustar00rootroot00000000000000(** Piece-wise linear interpolation from float-like types to float. *) open Core_kernel.Std open Piecewise_linear_intf (** This type constructor is how we expose, for instance, that [Make(K)(V).t] and [Stable.V1.Make(K)(V).t] are the same type (as long as [Stable.V1] is current). Likewise, if [K0.t = K1.t], then [Make(K0)(V).t = Make(K1)(V).t]. *) type ('key, 'value) t_ module type S = S with type ('k, 'v) t_ := ('k, 'v) t_ module Make (Key : Float_like) (Value : Float_like) : S with type key = Key.t with type value = Value.t type ('key, 'value) t_invertible module type S_invertible = S_invertible with type ('k, 'v) t_ := ('k, 'v) t_invertible module Make_invertible (Key : Float_like) (Value : Float_like) : S_invertible with type key = Key.t with type value = Value.t module Time : S with type key = Time.t with type value = float module Ofday : S with type key = Ofday.t with type value = float module Span : S with type key = Span.t with type value = float module Float : S with type key = float with type value = float module Int : S with type key = int with type value = float (** Note that applications of the following functors are only as stable as [Key] and [Value]. *) module Stable : sig module V1 : sig type nonrec ('key, 'value) t_ = ('key, 'value) t_ module Make (Key : Float_like) (Value : Float_like) : sig type t = (Key.t, Value.t) t_ with bin_io, compare, sexp end type nonrec ('key, 'value) t_invertible = ('key, 'value) t_invertible module Make_invertible (Key : Float_like) (Value : Float_like) : sig type t = (Key.t, Value.t) t_invertible with bin_io, compare, sexp end end end core-113.00.00/src/piecewise_linear_intf.ml000066400000000000000000000076701256461075500204410ustar00rootroot00000000000000open Core_kernel.Std module type Float_like = sig type t with bin_io, sexp include Floatable with type t := t end module type S = sig type ('k, 'v) t_ type key type value type t = (key, value) t_ with bin_io, sexp, compare (** [create] enforces that x (key) values are non-decreasing. It also enforces certain finiteness conditions: the x and y values must be finite (non-nan, and non-infinite), and differences of consecutive x values and consecutive y values must be finite. *) val create : (key * value) list -> t Or_error.t (** [get t x] evaluates the piecewise linear function [t] at [x]. It is possible to get discontinuous functions by using repeated x-values in the knots. In that case, the function is evaluated in such a way that it is right-continuous. For example, if [t] has knots [[(0.,0.5); (1.,1.5); (1.,10.); (2.,11.)]], then [get t 1.] returns [10.], [get t 0.999] returns [1.499], and [get t 1.001] returns [10.001]. *) val get : t -> key -> value (* O(1) *) val first_knot : t -> (key * value) option val last_knot : t -> (key * value) option (* O(n) *) val to_knots : t -> (key * value) list (* O(n) *) val to_knots' : t -> key array * value array (** [precache t] computes and stores a lookup table in [t] that speeds up subsequent calls to [get t]. Any call to [get] needs to find the knots that define the interval in which the key lies. This is done by bisection. Ordinarily the bisection starts on the whole domain of the piecewise linear function. Precaching builds a lookup table based on an equispaced division of the domain. This allows [get] to quickly determine a (potentially very) small initial interval on which to start the bisection. This works best for knots that are reasonably evenly distributed. [density] is the ratio of the size of the lookup table to the size of the knot array. Calling [precache] multiple times is safe. If the existing lookup density is the same or higher density than the requested density, the lookup table will not be recomputed. *) val precache : ?density:float (** default is [1] *) -> t -> unit (** Returns the [t] such that [get t key] = sum ([get t_i key]) * [weight_i]. This will fail if given an empty list as an argument, if any weights are not finite, or if any of the input [t]s has a discontinuity. The domain of each [t] does not have to be the same. The domain of the [t] that is returned will be the connected union of the domains. There are cases in [S_invertible] in which all [t]s could be valid and invertible, but the linear combination is not invertible. I.e. if one [t] is downward sloping, the other [t] is upward sloping, and the linear combination is sometimes upward and sometimes downward sloping. *) val create_from_linear_combination : (t * float) list -> t Or_error.t end module type S_invertible = sig (** [create] enforces that the x (key) values are strictly increasing. It also enforces that the y (value) values are either strictly increasing or strictly decreasing. These two properties give us invertibility. It also enforces certain finiteness conditions: the x and y values must be finite (non-nan, and non-infinite), and differences of consecutive x values and consecutive y values must be finite. (Conceivably, one might have a case where one wants to loosen the conditions on x and y values to non-strict monotonicity, so that one does not have true invertibility, but only a sort of formal invertibility. If that use case arises, a separate functor like [Make_formally_invertible] could be added, so that [Make_invertible] maintains its stricter semantics.) *) include S (** [get_inverse t value] is the inverse operation of [get t key]. *) val get_inverse : t -> value -> key end core-113.00.00/src/polymorphic_compare.ml000066400000000000000000000000501256461075500201460ustar00rootroot00000000000000include Core_kernel.Polymorphic_compare core-113.00.00/src/polymorphic_compare_intf.ml000066400000000000000000000000551256461075500211730ustar00rootroot00000000000000include Core_kernel.Polymorphic_compare_intf core-113.00.00/src/pretty_printer.ml000066400000000000000000000000431256461075500171670ustar00rootroot00000000000000include Core_kernel.Pretty_printer core-113.00.00/src/process_env.ml000066400000000000000000000026631256461075500164350ustar00rootroot00000000000000open Core_kernel.Std module Unix = Core_unix let ssh_client_var = "SSH_CLIENT" let parse_ssh_client_var = function | None -> Ok `Nowhere | Some s -> match String.split ~on:' ' s with | [] -> failwith "This should never happen, empty string splits as [\"\"]" (* Allow any SSH_CLIENT var containing an IP address as the first element. Normally, it should have three parts, but relaxing this constraint helps debugging/troubleshooting easier. *) | address :: _ -> Or_error.try_with (fun () -> `From (Unix.Inet_addr.of_string address)) |> (fun e -> Or_error.tag_arg e "Could not parse IP address in SSH_CLIENT" s <:sexp_of< string >>) let parse_ssh_client () = parse_ssh_client_var (Core_sys.getenv ssh_client_var) TEST_MODULE "process ssh client env" = struct let ip = "127.0.0.1" let inet_addr = Unix.Inet_addr.of_string ip TEST = parse_ssh_client_var None = Ok `Nowhere (* IP-only SSH_CLIENT env var, which maybe used for debugging and troubleshooting *) TEST = parse_ssh_client_var (Some ip) = Ok (`From inet_addr) (* Correctly formatted SSH_CLIENT env var *) TEST = parse_ssh_client_var (Some (ip ^ " 12345 67890")) = Ok (`From inet_addr) (* malformed ip *) TEST = Result.is_error (parse_ssh_client_var (Some "12345.67890")) TEST = Result.is_error (parse_ssh_client_var (Some "random string")) TEST = Result.is_error (parse_ssh_client_var (Some "")) end core-113.00.00/src/process_env.mli000066400000000000000000000004541256461075500166020ustar00rootroot00000000000000(** Utility functions for dealing with the environment. *) open Core_kernel.Std (** [parse_ssh_client] reads the [SSH_CLIENT] environment variable, retrieving the IP from which you are currently sshing. *) val parse_ssh_client : unit -> [ `From of Core_unix.Inet_addr.t | `Nowhere ] Or_error.t core-113.00.00/src/recvmmsg.c000066400000000000000000000057601256461075500155450ustar00rootroot00000000000000#define _GNU_SOURCE /* recvmmsg */ #include #include #include #include "ocaml_utils.h" #include "unix_utils.h" #include "socketaddr.h" #include "recvmmsg.h" #ifdef JSC_RECVMMSG int recvmmsg_assume_fd_is_nonblocking( value v_fd, struct iovec *iovecs, unsigned count, value v_srcs, struct mmsghdr *hdrs) { CAMLparam2(v_fd, v_srcs); CAMLlocal1(v_sockaddrs); size_t total_len = 0; unsigned i; int n_read; int save_source_addresses; int fd; if ((int) count < 0) { caml_failwith("recvmmsg_assume_fd_is_nonblocking: apparently negative count"); } { union sock_addr_union addrs[RECVMMSG_MAX_COUNT]; save_source_addresses = Is_block(v_srcs); fd = Int_val(v_fd); if (count > RECVMMSG_MAX_COUNT) { caml_failwith("recvmmsg_assume_fd_is_nonblocking: " "count exceeds RECVMMSG_MAX_COUNT"); } for (i = 0; i < count; i++) { hdrs[i].msg_hdr.msg_name = (save_source_addresses ? &addrs[i].s_gen : 0); hdrs[i].msg_hdr.msg_namelen = (save_source_addresses ? sizeof(addrs[i]) : 0); #if DEBUG fprintf(stderr, "i=%u, count=%u, save_source_addresses=%d\n", i, count, save_source_addresses); #endif total_len += iovecs[i].iov_len; hdrs[i].msg_hdr.msg_iov = &iovecs[i]; hdrs[i].msg_hdr.msg_iovlen = 1; hdrs[i].msg_hdr.msg_control = 0; hdrs[i].msg_hdr.msg_controllen = 0; hdrs[i].msg_hdr.msg_flags = 0; /* We completely ignore msg_flags and ancillary data (msg_control) for now. In the future, users may be interested in this. */ } /* This is only 64k in unix_utils.h, which we will very quickly overrun with recvmmsg and then maybe Jumbo frames. We have already observed an application filling over 32 recvmmsg buffers in a single call, in a test scenario. */ if (total_len > THREAD_IO_CUTOFF) { caml_enter_blocking_section(); n_read = recvmmsg(fd, hdrs, count, 0, 0); caml_leave_blocking_section(); } else { n_read = recvmmsg(fd, hdrs, count, 0, 0); } if (n_read > (int) count) { caml_failwith("recvmmsg_assume_fd_is_nonblocking: " "recvmmsg unexpectedly returned n_read > count"); } if (n_read == -1) n_read = -errno; else { if (save_source_addresses) { v_sockaddrs = Field(v_srcs, 0); if (!Is_block(v_sockaddrs)) { caml_invalid_argument("recvmmsg_assume_fd_is_nonblocking: " "v_sockaddrs is not an array"); } if (Wosize_val(v_sockaddrs) < count) { caml_invalid_argument("recvmmsg_assume_fd_is_nonblocking: " "length v_sockaddrs < count"); } for (i = 0; (int) i < n_read; i++) { value addr = alloc_sockaddr(&addrs[i], hdrs[i].msg_hdr.msg_namelen, -1); Store_field(v_sockaddrs, i, addr); } } } } CAMLreturnT(int, n_read); } #endif /* JSC_RECVMMSG */ core-113.00.00/src/recvmmsg.h000066400000000000000000000010551256461075500155430ustar00rootroot00000000000000#define _GNU_SOURCE /* struct mmsghdr */ #include #include "ocaml_utils.h" #ifdef JSC_RECVMMSG /* [recvmmsg] from [v_fd] into the [v_count] supplied [iovecs]. Save the from addresses in [v_srcs], if supplied. Use [hdrs], in particular, fully initializing and saving results there, including lengths of data read, flags, etc. */ int recvmmsg_assume_fd_is_nonblocking( value v_fd, struct iovec *iovecs, unsigned count, value v_srcs, struct mmsghdr *hdrs); #define RECVMMSG_MAX_COUNT 64 #endif /* JSC_RECVMMSG */ core-113.00.00/src/ref.ml000066400000000000000000000000301256461075500146450ustar00rootroot00000000000000include Core_kernel.Ref core-113.00.00/src/result.ml000066400000000000000000000000331256461075500154120ustar00rootroot00000000000000include Core_kernel.Result core-113.00.00/src/robustly_comparable.ml000066400000000000000000000000501256461075500201430ustar00rootroot00000000000000include Core_kernel.Robustly_comparable core-113.00.00/src/set_once.ml000066400000000000000000000000351256461075500156750ustar00rootroot00000000000000include Core_kernel.Set_once core-113.00.00/src/sexpable.ml000066400000000000000000000000351256461075500157010ustar00rootroot00000000000000include Core_kernel.Sexpable core-113.00.00/src/signal.ml000066400000000000000000000131741256461075500153630ustar00rootroot00000000000000open Core_kernel.Std let failwithf = Printf.failwithf include (Int : sig type t = int with bin_io include Comparable.S with type t := t include Hashable .S with type t := t end) external ml_caml_to_nonportable_signal_number : int -> int = "ml_caml_to_nonportable_signal_number" external ml_nonportable_to_caml_signal_number : int -> int = "ml_nonportable_to_caml_signal_number" let of_system_int t = ml_nonportable_to_caml_signal_number t let to_system_int t = ml_caml_to_nonportable_signal_number t let of_caml_int t = t let to_caml_int t = t type sys_behavior = [ | `Continue (** Continue the process if it is currently stopped *) | `Dump_core (** Terminate the process and dump core *) | `Ignore (** Ignore the signal *) | `Stop (** Stop the process *) | `Terminate (** Terminate the process *) ] with sexp let equal (t : t) t' = (t = t') include struct (* Please keep in sync with the list for to_string/sys_behavior *) open Sys let abrt = sigabrt let alrm = sigalrm let chld = sigchld let cont = sigcont let fpe = sigfpe let hup = sighup let ill = sigill let int = sigint let kill = sigkill let pipe = sigpipe let prof = sigprof let quit = sigquit let segv = sigsegv let stop = sigstop let term = sigterm let tstp = sigtstp let ttin = sigttin let ttou = sigttou let usr1 = sigusr1 let usr2 = sigusr2 let vtalrm = sigvtalrm let zero = 0 end exception Invalid_signal_mnemonic_or_number of string with sexp let to_string, of_string, default_sys_behavior = let known = [ ("sigabrt", abrt, `Dump_core); ("sigalrm", alrm, `Terminate); ("sigchld", chld, `Ignore); ("sigcont", cont, `Continue); ("sigfpe", fpe, `Dump_core); ("sighup", hup, `Terminate); ("sigill", ill, `Dump_core); ("sigint", int, `Terminate); ("sigkill", kill, `Terminate); ("sigpipe", pipe, `Terminate); ("sigprof", prof, `Terminate); ("sigquit", quit, `Dump_core); ("sigsegv", segv, `Dump_core); ("sigstop", stop, `Stop); ("sigterm", term, `Terminate); ("sigtstp", tstp, `Stop); ("sigttin", ttin, `Stop); ("sigttou", ttou, `Stop); ("sigusr1", usr1, `Terminate); ("sigusr2", usr2, `Terminate); ("sigvtalrm", vtalrm, `Terminate); ("sigzero", zero, `Ignore); ] in let str_tbl = Int.Table.create ~size:1 () in let int_tbl = String.Table.create ~size:1 () in let behavior_tbl = Int.Table.create ~size:1 () in List.iter known ~f:(fun (name, s, behavior) -> Hashtbl.set str_tbl ~key:s ~data:name; Hashtbl.set int_tbl ~key:name ~data:s; Hashtbl.set behavior_tbl ~key:s ~data:behavior); (* For unknown signal numbers, [to_string] returns a meaningful string, while [default_sys_behavior] has to raise an exception because we don't know what the right answer is. *) let to_string s = match Hashtbl.find str_tbl s with | None -> "" | Some string -> string in let of_string s = let s = String.lowercase (String.strip s) in match Hashtbl.find int_tbl s with | Some sn -> sn | None -> if String.is_prefix s ~prefix:" raise (Invalid_signal_mnemonic_or_number s) else raise (Invalid_signal_mnemonic_or_number s) in let default_sys_behavior s = match Hashtbl.find behavior_tbl s with | None -> raise (Invalid_argument ("Signal.default_sys_behavior: unknown signal " ^ Int.to_string s)) | Some behavior -> behavior in to_string, of_string, default_sys_behavior ;; exception Expected_atom of Sexplib.Sexp.t with sexp let sexp_of_t t = Sexplib.Sexp.Atom (to_string t) let t_of_sexp s = match s with | Sexplib.Sexp.Atom s -> of_string s | _ -> raise (Expected_atom s) ;; type pid_spec = [ `Pid of Pid.t | `My_group | `Group of Pid.t ] ;; let pid_spec_to_int = function | `Pid pid -> Pid.to_int pid | `My_group -> 0 | `Group pid -> ~- (Pid.to_int pid) ;; let pid_spec_to_string p = Int.to_string (pid_spec_to_int p) let send signal pid_spec = try UnixLabels.kill ~pid:(pid_spec_to_int pid_spec) ~signal; `Ok with Unix.Unix_error (Unix.ESRCH, _, _) -> `No_such_process ;; let send_i t pid_spec = match send t pid_spec with | `Ok | `No_such_process -> () ;; let send_exn t pid_spec = match send t pid_spec with | `Ok -> () | `No_such_process -> failwithf "Signal.send_exn %s pid:%s" (to_string t) (pid_spec_to_string pid_spec) () ;; module Expert = struct type behavior = [ `Default | `Ignore | `Handle of t -> unit ] module Behavior = struct let of_caml = function | Sys.Signal_default -> `Default | Sys.Signal_ignore -> `Ignore | Sys.Signal_handle f -> `Handle f let to_caml = function | `Default -> Sys.Signal_default | `Ignore -> Sys.Signal_ignore | `Handle f -> Sys.Signal_handle (fun t -> Exn.handle_uncaught_and_exit (fun () -> f t)) ;; end let signal t behavior = Behavior.of_caml (Sys.signal t (Behavior.to_caml behavior)) ;; let set t behavior = ignore (signal t behavior) let handle t f = set t (`Handle f) end open Expert let handle_default t = set t `Default let ignore t = set t `Ignore type sigprocmask_command = [ `Set | `Block | `Unblock ] let sigprocmask mode sigs = let mode = match mode with | `Block -> Unix.SIG_BLOCK | `Unblock -> Unix.SIG_UNBLOCK | `Set -> Unix.SIG_SETMASK in Unix.sigprocmask mode sigs ;; let sigpending = Unix.sigpending let sigsuspend = Unix.sigsuspend let can_send_to pid = try send_exn zero (`Pid pid); true with | _ -> false ;; core-113.00.00/src/signal.mli000066400000000000000000000153711256461075500155350ustar00rootroot00000000000000open Core_kernel.Std type t with bin_io, sexp include Comparable.S with type t := t include Hashable.S with type t := t include Stringable.S with type t := t val equal : t -> t -> bool (** [of_system_int] and [to_system_int] return and take respectively a signal number corresponding to those in the system's /usr/include/bits/signum.h (or equivalent). It is not guaranteed that these numbers are portable across any given pair of systems -- although some are defined as standard by POSIX. *) val of_system_int : int -> t val to_system_int : t -> int (** [of_caml_int] constructs a Signal.t given an O'Caml internal signal number. This is only for the use of the Core_unix module. *) val of_caml_int : int -> t val to_caml_int : t -> int (** [to_string t] returns a human-readable name: "sigabrt", "sigalrm", ... *) val to_string : t -> string (** The default behaviour of the system if these signals trickle to the top level of a program. See include/linux/kernel.h in the Linux kernel source tree (not the file /usr/include/linux/kernel.h). *) type sys_behavior = [ | `Continue (** Continue the process if it is currently stopped*) | `Dump_core (** Terminate the process and dump core *) | `Ignore (** Ignore the signal*) | `Stop (** Stop the process *) | `Terminate (** Terminate the process *) ] with sexp (** [default_sys_behavior t] Query the default system behavior for a signal. *) val default_sys_behavior : t -> sys_behavior (** [handle_default t] is [set t `Default]. *) val handle_default : t -> unit (** [ignore t] is [set t `Ignore]. *) val ignore : t -> unit type pid_spec = [ `Pid of Pid.t | `My_group | `Group of Pid.t ] (** [send signal pid_spec] sends [signal] to the processes specified by [pid_spec]. [send_i] is like [send], except that it silently returns if the specified processes don't exist. [send_exn] is like [send], except that it raises if the specified processes don't exist. All of [send], [send_i], and [send_exn] raise if you don't have permission to send the signal to the specified processes or if [signal] is unknown. *) val send : t -> pid_spec -> [ `Ok | `No_such_process ] val send_i : t -> pid_spec -> unit val send_exn : t -> pid_spec -> unit (** [can_send_to pid] returns true if [pid] is running and the current process has permission to send it signals. *) val can_send_to : Pid.t -> bool type sigprocmask_command = [ `Set | `Block | `Unblock ] (** [sigprocmask cmd sigs] changes the set of blocked signals. * If [cmd] is [`Set], blocked signals are set to those in the list [sigs]. * If [cmd] is [`Block], the signals in [sigs] are added to the set of blocked * signals. * If [cmd] is [`Unblock], the signals in [sigs] are removed from the set of * blocked signals. * [sigprocmask] returns the set of previously blocked signals. *) val sigprocmask : sigprocmask_command -> t list -> t list (** [sigpending ()] returns the set of blocked signals that are currently * pending. *) val sigpending : unit -> t list (** [sigsuspend sigs] atomically sets the blocked signals to [sigs] and waits for * a non-ignored, non-blocked signal to be delivered. On return, the blocked * signals are reset to their initial value. *) val sigsuspend : t list -> unit (** Specific signals, along with their default behavior and meaning. *) val abrt : t (** [Dump_core] Abnormal termination *) val alrm : t (** [Terminate] Timeout *) val chld : t (** [Ignore] Child process terminated *) val cont : t (** [Continue] Continue *) val fpe : t (** [Dump_core] Arithmetic exception *) val hup : t (** [Terminate] Hangup on controlling terminal *) val ill : t (** [Dump_core] Invalid hardware instruction *) val int : t (** [Terminate] Interactive interrupt (ctrl-C) *) val kill : t (** [Terminate] Termination (cannot be ignored) *) val pipe : t (** [Terminate] Broken pipe *) val prof : t (** [Terminate] Profiling interrupt *) val quit : t (** [Dump_core] Interactive termination *) val segv : t (** [Dump_core] Invalid memory reference *) val stop : t (** [Stop] Stop *) val term : t (** [Terminate] Termination *) val tstp : t (** [Stop] Interactive stop *) val ttin : t (** [Stop] Terminal read from background process *) val ttou : t (** [Stop] Terminal write from background process *) val usr1 : t (** [Terminate] Application-defined signal 1 *) val usr2 : t (** [Terminate] Application-defined signal 2 *) val vtalrm : t (** [Terminate] Timeout in virtual time *) val zero : t (** [Ignore] No-op; can be used to test whether the target process exists and the current process has permission to signal it *) (** The [Expert] module contains functions that novice users should avoid, due to their complexity. An OCaml signal handler can run at any time, which introduces all the semantic complexities of multithreading. It is much easier to use Async's signal handling, see {!Async_unix.Signal}, which does not involve multithreading, and runs user code as ordinary Async jobs. Also, beware that there can only be a single OCaml signal handler for any signal, so handling a signal with a [Core] signal handler will interfere if Async is attempting to handle the same signal. All signal handler functions are called with [Exn.handle_uncaught_and_exit], to prevent the signal handler from raising, because raising from a signal handler could raise to any allocation or GC point in any thread, which would be impossible to reason about. If you do use [Core] signal handlers, you should strive to make the signal handler perform a simple idempotent action, like setting a ref. *) module Expert : sig type behavior = [ `Default | `Ignore | `Handle of t -> unit ] (** [signal t] sets the behavior of the system on receipt of signal [t] and returns the behavior previously associated with [t]. If [t] is not available on your system, [signal] raises. *) val signal : t -> behavior -> behavior (** [set t b] is [ignore (signal t b)] *) val set : t -> behavior -> unit (** [handle t f] is [set t (`Handle f)]. *) val handle : t -> (t -> unit) -> unit end core-113.00.00/src/signal_stubs.c000066400000000000000000000005421256461075500164100ustar00rootroot00000000000000#include "ocaml_utils.h" CAMLextern int caml_rev_convert_signal_number(int); CAMLprim value ml_caml_to_nonportable_signal_number(value v_signo) { return Val_int(caml_convert_signal_number(Int_val(v_signo))); } CAMLprim value ml_nonportable_to_caml_signal_number(value v_signo) { return Val_int(caml_rev_convert_signal_number(Int_val(v_signo))); } core-113.00.00/src/socketaddr.h000066400000000000000000000017161256461075500160470ustar00rootroot00000000000000#include #include #include #include #include #include union sock_addr_union { struct sockaddr s_gen; struct sockaddr_un s_unix; struct sockaddr_in s_inet; #ifdef HAS_IPV6 struct sockaddr_in6 s_inet6; #endif }; #ifdef HAS_SOCKLEN_T typedef socklen_t socklen_param_type; #else typedef int socklen_param_type; #endif extern void get_sockaddr (value mladdr, union sock_addr_union * addr /*out*/, socklen_param_type * addr_len /*out*/); CAMLexport value alloc_sockaddr (union sock_addr_union * addr /*in*/, socklen_param_type addr_len, int close_on_error); CAMLexport value alloc_inet_addr (struct in_addr * inaddr); #define GET_INET_ADDR(v) (*((struct in_addr *) (v))) #ifdef HAS_IPV6 CAMLexport value alloc_inet6_addr (struct in6_addr * inaddr); #define GET_INET6_ADDR(v) (*((struct in6_addr *) (v))) #endif core-113.00.00/src/source_code_position.ml000066400000000000000000000000511256461075500203120ustar00rootroot00000000000000include Core_kernel.Source_code_position core-113.00.00/src/source_code_position0.ml000066400000000000000000000000521256461075500203730ustar00rootroot00000000000000include Core_kernel.Source_code_position0 core-113.00.00/src/span.ml000066400000000000000000000441621256461075500150500ustar00rootroot00000000000000open Core_kernel.Std module Stable = struct module V1 = struct module Parts = struct type t = { sign : Float.Sign.t; hr : int; min : int; sec : int; ms : int; us : int; } with sexp end module type Like_a_float = sig type t with bin_io include Comparable.S_common with type t := t include Comparable.With_zero with type t := t include Hashable_binable with type t := t include Stringable with type t := t include Floatable with type t := t val (+) : t -> t -> t val (-) : t -> t -> t val zero : t val robust_comparison_tolerance : t val abs : t -> t val neg : t -> t val scale : t -> float -> t end module T : sig type t = private float with bin_io include Like_a_float with type t := t include Robustly_comparable with type t := t module Constant : sig val nanoseconds_per_second : float val microseconds_per_second : float val milliseconds_per_second : float val nanosecond : t val microsecond : t val millisecond : t val second : t val minute : t val hour : t val day : t end val to_parts : t -> Parts.t end = struct type t = float (* IF THIS REPRESENTATION EVER CHANGES, ENSURE THAT EITHER (1) all values serialize the same way in both representations, or (2) you add a new Time.Span version to stable.ml *) include (Float : Like_a_float with type t := t) (* due to precision limitations in float we can't expect better than microsecond precision *) include Core_kernel.Float_robust_compare.Make (struct let robust_comparison_tolerance = 1E-6 end) (* this prevents any worry about having these very common names redefined below and makes their usage within this module safer. Constant is included at the very bottom to re-export these constants in a more convenient way *) module Constant = struct let nanoseconds_per_second = 1E9 let microseconds_per_second = 1E6 let milliseconds_per_second = 1E3 (* spans are stored as a float in seconds *) let nanosecond = of_float (1. /. nanoseconds_per_second) let microsecond = of_float (1. /. microseconds_per_second) let millisecond = of_float (1. /. milliseconds_per_second) let second = of_float 1. let minute = of_float 60. let hour = of_float (60. *. 60.) let day = of_float (24. *. 60. *. 60.) end let to_parts_64 t = let t = to_float t *. 1.E6 in let sign = Float.sign t in let t = match sign with | Float.Sign.Neg -> Float.neg t | Float.Sign.Pos | Float.Sign.Zero -> t in let t = Float.iround_exn ~dir:`Nearest t in let sec = t / 1_000_000 in let min = sec / 60 in let sec = sec mod 60 in let hr = min / 60 in let min = min mod 60 in let us = t mod 1_000_000 in let ms = us / 1_000 in let us = us mod 1_000 in {Parts. sign = sign; hr = hr; min = min; sec = sec; ms = ms; us = us; } let to_parts_32 t = let t = Float.round (to_float t *. 1E6) /. 1E6 in let sign = Float.sign t in let t = match sign with | Float.Sign.Neg -> Float.neg t | Float.Sign.Pos | Float.Sign.Zero -> t in let parts = Float.modf t in let intval = Float.iround_exn ~dir:`Down (Float.Parts.integral parts) in let min = intval / 60 in let sec = intval mod 60 in let hr = min / 60 in let min = min mod 60 in let us = Float.iround_exn ~dir:`Nearest (Float.Parts.fractional parts *. 1.E6) in let ms = us / 1_000 in let us = us mod 1_000 in {Parts. sign = sign; hr = hr; min = min; sec = sec; ms = ms; us = us; } let to_parts = if Int.(=) Core_sys.word_size 64 then to_parts_64 else to_parts_32 end let format_decimal n tenths units = assert (tenths >= 0 && tenths < 10); if n < 10 && tenths <> 0 then sprintf "%d.%d%s" n tenths units else sprintf "%d%s" n units let to_short_string span = let open Parts in let parts = T.to_parts span in let s = if parts.hr > 24 then format_decimal (parts.hr / 24) (Int.of_float (Float.of_int (parts.hr % 24) /. 2.4)) "d" else if parts.hr > 0 then format_decimal parts.hr (parts.min / 6) "h" else if parts.min > 0 then format_decimal parts.min (parts.sec / 6) "m" else if parts.sec > 0 then format_decimal parts.sec (parts.ms / 100) "s" else if parts.ms > 0 then format_decimal parts.ms (parts.us / 100) "ms" else sprintf "%ius" parts.us in if parts.sign = Float.Sign.Neg then "-" ^ s else s let (/) t f = T.of_float ((t : T.t :> float) /. f) let (//) (f:T.t) (t:T.t) = (f :> float) /. (t :> float) (* Multiplying by 1E3 is more accurate than division by 1E-3 *) let to_ns (x:T.t) = (x :> float) *. T.Constant.nanoseconds_per_second let to_us (x:T.t) = (x :> float) *. T.Constant.microseconds_per_second let to_ms (x:T.t) = (x :> float) *. T.Constant.milliseconds_per_second let to_sec (x:T.t) = (x :> float) let to_min x = x // T.Constant.minute let to_hr x = x // T.Constant.hour let to_day x = x // T.Constant.day let ( ** ) f (t:T.t) = T.of_float (f *. (t :> float)) (* Division by 1E3 is more accurate than multiplying by 1E-3 *) let of_ns x = T.of_float (x /. T.Constant.nanoseconds_per_second) let of_us x = T.of_float (x /. T.Constant.microseconds_per_second) let of_ms x = T.of_float (x /. T.Constant.milliseconds_per_second) let of_sec x = T.of_float x let of_int_sec x = T.of_float (Float.of_int x) let of_min x = x ** T.Constant.minute let of_hr x = x ** T.Constant.hour let of_day x = x ** T.Constant.day let randomize (t:T.t) ~percent = if (percent < 0. || percent > 1.0) then invalid_argf "percent must be between 0 and 1, %f given" percent (); let t = to_sec t in let distance = Random.float (t *. percent) in of_sec (if Random.bool () then t +. distance else t -. distance) ;; let create ?(sign=Float.Sign.Pos) ?(day = 0) ?(hr = 0) ?(min = 0) ?(sec = 0) ?(ms = 0) ?(us = 0) () = let (+) = T.(+) in let t = of_day (Float.of_int day) + of_hr (Float.of_int hr) + of_min (Float.of_int min) + of_sec (Float.of_int sec) + of_ms (Float.of_int ms) + of_us (Float.of_int us) in match sign with | Float.Sign.Neg -> T.(-) T.zero t | Float.Sign.Pos | Float.Sign.Zero -> t include T include Constant (* WARNING: if you are going to change this function in any material way, make sure you update Stable appropriately. *) let of_string_v1_v2 (s:string) ~is_v2 = try begin match s with | "" -> failwith "empty string" | _ -> let float n = match (String.drop_suffix s n) with | "" -> failwith "no number given" | s -> let v = Float.of_string s in Validate.maybe_raise (Float.validate_ordinary v); v in let len = String.length s in match s.[Int.(-) len 1] with | 's' -> if Int.(>=) len 2 && Char.(=) s.[Int.(-) len 2] 'm' then of_ms (float 2) else if is_v2 && Int.(>=) len 2 && Char.(=) s.[Int.(-) len 2] 'u' then of_us (float 2) else if is_v2 && Int.(>=) len 2 && Char.(=) s.[Int.(-) len 2] 'n' then of_ns (float 2) else T.of_float (float 1) | 'm' -> of_min (float 1) | 'h' -> of_hr (float 1) | 'd' -> of_day (float 1) | _ -> if is_v2 then failwith "Time spans must end in ns, us, ms, s, m, h, or d." else failwith "Time spans must end in ms, s, m, h, or d." end with exn -> invalid_argf "Span.of_string could not parse '%s': %s" s (Exn.to_string exn) () let of_sexp_error_exn exn sexp = of_sexp_error (Exn.to_string exn) sexp exception T_of_sexp of Sexp.t * exn with sexp exception T_of_sexp_expected_atom_but_got of Sexp.t with sexp let t_of_sexp_v1_v2 sexp ~is_v2 = match sexp with | Sexp.Atom x -> begin try of_string_v1_v2 x ~is_v2 with exn -> of_sexp_error_exn (T_of_sexp (sexp, exn)) sexp end | Sexp.List _ -> of_sexp_error_exn (T_of_sexp_expected_atom_but_got sexp) sexp let string ~is_v2 suffix float = if is_v2 (* This is the same float-to-string conversion used in [Float.sexp_of_t]. It's like [Float.to_string_round_trippable], but may leave off trailing period. *) then !Sexplib.Conv.default_string_of_float float ^ suffix else sprintf "%g%s" float suffix (* WARNING: if you are going to change this function in any material way, make sure you update Stable appropriately. *) (* I'd like it to be the case that you could never construct an infinite span, but I can't think of a good way to enforce it. So this to_string function can produce strings that will raise an exception when they are fed to of_string *) let to_string_v1_v2 (t:T.t) ~is_v2 = (* this is a sad broken abstraction... *) let module C = Float.Class in match Float.classify (t :> float) with | C.Subnormal | C.Zero -> "0s" | C.Infinite -> if T.(>) t T.zero then "inf" else "-inf" | C.Nan -> "nan" | C.Normal -> let (<) = T.(<) in let abs_t = T.of_float (Float.abs (t :> float)) in if is_v2 && abs_t < T.Constant.microsecond then string ~is_v2 "ns" (to_ns t) else if is_v2 && abs_t < T.Constant.millisecond then string ~is_v2 "us" (to_us t) else if abs_t < T.Constant.second then string ~is_v2 "ms" (to_ms t) else if abs_t < T.Constant.minute then string ~is_v2 "s" (to_sec t) else if abs_t < T.Constant.hour then string ~is_v2 "m" (to_min t) else if abs_t < T.Constant.day then string ~is_v2 "h" (to_hr t) else string ~is_v2 "d" (to_day t) let sexp_of_t_v1_v2 t ~is_v2 = Sexp.Atom (to_string_v1_v2 t ~is_v2) let t_of_sexp sexp = t_of_sexp_v1_v2 sexp ~is_v2:false let sexp_of_t t = sexp_of_t_v1_v2 t ~is_v2:false let of_string s = of_string_v1_v2 s ~is_v2:false let to_string t = to_string_v1_v2 t ~is_v2:false end module V2 = struct include V1 let t_of_sexp sexp = t_of_sexp_v1_v2 sexp ~is_v2:true let sexp_of_t t = sexp_of_t_v1_v2 t ~is_v2:true let of_string s = of_string_v1_v2 s ~is_v2:true let to_string t = to_string_v1_v2 t ~is_v2:true end TEST_MODULE "Span.V1" = Core_kernel.Stable_unit_test.Make (struct include V1 let equal t1 t2 = Int.(=) 0 (compare t1 t2) let tests = let span = of_sec in [ span 99e-12, "9.9e-08ms", "\018\006\211\115\129\054\219\061"; span 1.2e-9, "1.2e-06ms", "\076\206\097\227\167\157\020\062"; span 0.000001, "0.001ms", "\141\237\181\160\247\198\176\062"; span 0.707, "707ms", "\057\180\200\118\190\159\230\063"; span 42., "42s", "\000\000\000\000\000\000\069\064"; span 1234.56, "20.576m", "\010\215\163\112\061\074\147\064"; span 39_996., "11.11h", "\000\000\000\000\128\135\227\064"; span 80000006.4, "925.926d", "\154\153\153\025\208\018\147\065"; ] end) TEST_MODULE "Span.V2" = Core_kernel.Stable_unit_test.Make (struct include V2 let equal t1 t2 = Int.(=) 0 (compare t1 t2) let tests = let span = of_sec in [ span 99e-12, "0.098999999999999991ns", "\018\006\211\115\129\054\219\061"; span 1.2e-9, "1.2ns", "\076\206\097\227\167\157\020\062"; span 0.000001, "1us", "\141\237\181\160\247\198\176\062"; span 0.707, "707ms", "\057\180\200\118\190\159\230\063"; span 42., "42s", "\000\000\000\000\000\000\069\064"; span 1234.56, "20.576m", "\010\215\163\112\061\074\147\064"; span 39_996., "11.11h", "\000\000\000\000\128\135\227\064"; span 80000006.4, "925.926d", "\154\153\153\025\208\018\147\065"; ] end) end include Stable.V2 let sexp_of_t = Stable.V1.sexp_of_t let to_string = Stable.V1.to_string TEST_MODULE "conversion compatibility" = struct let tests = let span = of_sec in [ span 99e-12 ; span 1.2e-9 ; span 0.000001 ; span 0.707 ; span 42. ; span 1234.56 ; span 39_996. ; span 80000006.4 ] TEST_UNIT = List.iter tests ~f:(fun t -> begin (* Output must match Stable.V1: *) <:test_result< Sexp.t >> (sexp_of_t t) ~expect:(Stable.V1.sexp_of_t t); <:test_result< string >> (to_string t) ~expect:(Stable.V1.to_string t); (* Stable.V1 must accept output (slightly redundant): *) <:test_result< t >> (Stable.V1.t_of_sexp (sexp_of_t t)) ~expect:t; <:test_result< t >> (Stable.V1.of_string (to_string t)) ~expect:t; (* Stable.V2 should accept output: *) <:test_result< t >> (Stable.V2.t_of_sexp (sexp_of_t t)) ~expect:t; <:test_result< t >> (Stable.V2.of_string (to_string t)) ~expect:t; (* Should accept Stable.V1 output: *) <:test_result< t >> (t_of_sexp (Stable.V1.sexp_of_t t)) ~expect:t; <:test_result< t >> (of_string (Stable.V1.to_string t)) ~expect:t; (* Should accept Stable.V2 output: *) <:test_result< t >> (t_of_sexp (Stable.V2.sexp_of_t t)) ~expect:t; <:test_result< t >> (of_string (Stable.V2.to_string t)) ~expect:t; (* Must round-trip: *) <:test_result< t >> (t_of_sexp (sexp_of_t t)) ~expect:t; <:test_result< t >> (of_string (to_string t)) ~expect:t; end) end module Unit_of_time = struct type t = | Nanosecond | Microsecond | Millisecond | Second | Minute | Hour | Day with sexp, compare end TEST_UNIT "Span.Unit_of_time.t" = <:test_result> (<:compare> Nanosecond Microsecond) ~expect:(-1); <:test_result> (<:compare> Microsecond Millisecond) ~expect:(-1); <:test_result> (<:compare> Millisecond Second) ~expect:(-1); <:test_result> (<:compare> Second Minute) ~expect:(-1); <:test_result> (<:compare> Minute Hour) ~expect:(-1); <:test_result> (<:compare> Hour Day) ~expect:(-1) let to_unit_of_time t : Unit_of_time.t = let abs_t = abs t in if abs_t >= day then Day else if abs_t >= hour then Hour else if abs_t >= minute then Minute else if abs_t >= second then Second else if abs_t >= millisecond then Millisecond else if abs_t >= microsecond then Microsecond else Nanosecond let of_unit_of_time : Unit_of_time.t -> t = function | Nanosecond -> nanosecond | Microsecond -> microsecond | Millisecond -> millisecond | Second -> second | Minute -> minute | Hour -> hour | Day -> day let to_string_hum ?(delimiter='_') ?(decimals=3) ?(align_decimal=false) ?unit_of_time t = let float, suffix = match Option.value unit_of_time ~default:(to_unit_of_time t) with | Day -> to_day t, "d" | Hour -> to_hr t, "h" | Minute -> to_min t, "m" | Second -> to_sec t, "s" | Millisecond -> to_ms t, "ms" | Microsecond -> to_us t, "us" | Nanosecond -> to_ns t, "ns" in let prefix = Float.to_string_hum float ~delimiter ~decimals ~strip_zero:(not align_decimal) in let suffix = if align_decimal && Int.(=) (String.length suffix) 1 then suffix ^ " " else suffix in prefix ^ suffix TEST_UNIT "Span.to_string_hum" = <:test_result> (to_string_hum nanosecond) ~expect:"1ns"; <:test_result> (to_string_hum day) ~expect:"1d"; <:test_result> (to_string_hum ~decimals:6 day) ~expect:"1d"; <:test_result> (to_string_hum ~decimals:6 ~align_decimal:false day) ~expect:"1d"; <:test_result> (to_string_hum ~decimals:6 ~align_decimal:true day) ~expect:"1.000000d "; <:test_result> (to_string_hum ~decimals:6 ~align_decimal:true ~unit_of_time:Day (hour + minute)) ~expect:"0.042361d " include Pretty_printer.Register (struct type nonrec t = t let to_string = to_string let module_name = "Core.Std.Time.Span" end) module C = struct type t = T.t with bin_io type comparator_witness = T.comparator_witness let comparator = T.comparator (* In 108.06a and earlier, spans in sexps of Maps and Sets were raw floats. From 108.07 through 109.13, the output format remained raw as before, but both the raw and pretty format were accepted as input. From 109.14 on, the output format was changed from raw to pretty, while continuing to accept both formats. Once we believe most programs are beyond 109.14, we will switch the input format to no longer accept raw. *) let sexp_of_t = sexp_of_t let t_of_sexp sexp = match Option.try_with (fun () -> T.of_float (Float.t_of_sexp sexp)) with | Some t -> t | None -> t_of_sexp sexp ;; end module Map = Map.Make_binable_using_comparator (C) module Set = Set.Make_binable_using_comparator (C) TEST = Set.equal (Set.of_list [hour]) (Set.t_of_sexp (Sexp.List [Float.sexp_of_t (to_float hour)])) ;; (* We should be robustly equal within a microsecond *) TEST = (=.) zero microsecond TEST = not ((=.) zero (of_ns 1001.0)) core-113.00.00/src/span.mli000066400000000000000000000126621256461075500152210ustar00rootroot00000000000000open Core_kernel.Std type t = private float with bin_io, sexp (* number of seconds *) (* Parts represents the individual parts of a Span as if it were written out (it is the counterpart to create). For example, (sec 90.) is represented by {Parts.hr = 0; min = 1; sec = 30; ms = 0}. The fields will always be positive. *) module Parts : sig type t = private { sign : Float.Sign.t; hr : int; min : int; sec : int; ms : int; us : int; } with sexp end include Comparable_binable with type t := t include Comparable.With_zero with type t := t include Floatable with type t := t include Hashable_binable with type t := t include Pretty_printer.S with type t := t include Robustly_comparable with type t := t (* String converters and sexp converters allow for specifying of time spans in various units after a leading float (e.g. 45s, 3h, or 1d): ms - milliseconds s - seconds m - minutes h - hours d - days The outgoing conversion functions use these units as well, choosing the largest available type. For instance, if it's a bit greater than or equal to 1 hour, the span will be rendered in hours, (Time.to_string (Time.of_string "66m") = "1.1h"). As of [Stable.V2], [of_string] and [t_of_sexp] also accept "us"=microseconds and "ns"=nanoseconds suffixes. [Stable.V2] will produce these suffixes, but for compatibility with [Stable.V1], ordinary [to_string] and [sexp_of_t] will not, for now. Once use of the new [of_] family is more widespread, we will switch the [to_] family to the more expressive format. In the meantime, you can get [ns] and [us] suffixes by using [to_string_hum]. *) val to_string : t -> string val of_string : string -> t (* values *) val nanosecond : t val microsecond : t val millisecond : t val second : t val minute : t val hour : t val day : t (* 10^-6 seconds, used in robustly comparable operators (<., >., =., ...) to determine equality *) val robust_comparison_tolerance : t val zero : t (* [create ?sign ?day ?hr ?min ?sec ?ms ?us ()] Create a span from the given parts. All parts are assumed to be positive (no checking is done by the function) and the sign of the final span is given by [sign] which is positive by default. *) val create : ?sign:Float.Sign.t -> ?day:int -> ?hr:int -> ?min:int -> ?sec:int -> ?ms:int -> ?us:int -> unit -> t val to_parts : t -> Parts.t (* converters *) val of_ns : float -> t val of_us : float -> t val of_ms : float -> t val of_sec : float -> t val of_int_sec : int -> t val of_min : float -> t val of_hr : float -> t val of_day : float -> t val to_ns : t -> float val to_us : t -> float val to_ms : t -> float val to_sec : t -> float val to_min : t -> float val to_hr : t -> float val to_day : t -> float (** {6 Basic operations on spans} *) val (+) : t -> t -> t val (-) : t -> t -> t val abs : t -> t (** absolute value *) val neg : t -> t (** negation *) val scale : t -> float -> t val (/) : t -> float -> t val (//) : t -> t -> float (** [to_short_string t] pretty-prints approximate time span using no more than five characters if the span is positive, and six if the span is negative. Examples {ul {li ["4h"] = 4 hours} {li ["5m"] = 5 minutes} {li ["4s"] = 4 seconds} {li ["10ms"] = 10 milliseconds} } only the most significant denomination is shown. *) val to_short_string : t -> string module Unit_of_time : sig (** Represents a unit of time for purposes of human-readable display. Comparison respects Nanosecond < Microsecond < Millisecond < Second < Minute < Hour < Day. *) type t = | Nanosecond | Microsecond | Millisecond | Second | Minute | Hour | Day with sexp, compare end (** [to_unit_of_time t] = [Day] if [abs t >= day], [Hour] if [abs t >= hour], and so on down to [Microsecond] if [abs t >= microsecond], and [Nanosecond] otherwise. *) val to_unit_of_time : t -> Unit_of_time.t (** [of_unit_of_time unit_of_time] produces a [t] representing the corresponding span. *) val of_unit_of_time : Unit_of_time.t -> t (** [to_string_hum t ~delimiter ~decimals ~align_decimal ~unit_of_time] formats [t] using the given unit of time, or the largest appropriate units if none is specified, among "d"=day, "h"=hour, "m"=minute, "s"=second, "ms"=millisecond, "us"=microsecond, or "ns"=nanosecond. The magnitude of the time span in the chosen unit is formatted by: [Float.to_string_hum ~delimiter ~decimals ~strip_zero:(not align_decimal)] If [align_decimal] is true, the single-character suffixes are padded with an extra space character. In combination with not stripping zeroes, this means that the decimal point will occur a fixed number of characters from the end of the string. *) val to_string_hum : ?delimiter:char (** defaults to ['_'] *) -> ?decimals:int (** defaults to 3 *) -> ?align_decimal:bool (** defaults to [false] *) -> ?unit_of_time:Unit_of_time.t (** defaults to [to_unit_of_time t] *) -> t -> string (** [randomize t ~percent] returns a span +/- percent * original span. Percent must be between 0 and 1, and must be positive. *) val randomize : t -> percent:float -> t module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io, compare end module V2 : sig type nonrec t = t with sexp, bin_io, compare end end core-113.00.00/src/squeue.ml000066400000000000000000000062071256461075500154140ustar00rootroot00000000000000open Core_kernel.Std module Queue = Linked_queue module Mutex = Core_mutex (** Synchronized queue type *) type 'a t = { ev_q: 'a Queue.t; maxsize: int; mutex: Mutex.t sexp_opaque; not_empty: Condition.t sexp_opaque; not_full: Condition.t sexp_opaque; finally:unit -> unit; } with sexp_of let create maxsize = let ev_q = Queue.create () in let mutex = Mutex.create () in let not_empty = Condition.create () in let not_full = Condition.create () in { ev_q = ev_q; mutex = mutex; not_empty = not_empty; not_full = not_full; maxsize = maxsize; finally = (fun () -> let len = Queue.length ev_q in if len <> 0 then Condition.signal not_empty; if len < maxsize then Condition.signal not_full; Mutex.unlock mutex); } ;; let wrap q run = Mutex.lock q.mutex; protect ~f:run ~finally:q.finally ;; let clear q = let run () = Queue.clear q.ev_q in wrap q run ;; let wait_not_full q = while Queue.length q.ev_q >= q.maxsize do Condition.wait q.not_full q.mutex done let wait_not_empty q = while Queue.is_empty q.ev_q do Condition.wait q.not_empty q.mutex done (** Pushes an event on the queue if there's room *) let push q x = let run () = wait_not_full q; Queue.enqueue q.ev_q x; in wrap q run (** Pushes an event on the queue, unconditionally, may grow the queue past maxsize *) let push_uncond q x = let run () = Queue.enqueue q.ev_q x in wrap q run (** Pushes an event on the queue if the queue is less than maxsize, otherwise drops it. Returns true if the push was successful *) let push_or_drop q x = let run () = if Queue.length q.ev_q < q.maxsize then begin Queue.enqueue q.ev_q x; true end else false in wrap q run (** computes the length of the queue *) let length q = let run () = Queue.length q.ev_q in wrap q run (** Pops an event off of the queue, blocking until something is available *) let pop q = let run () = wait_not_empty q; Queue.dequeue_exn q.ev_q in wrap q run (** Pops an event off of the queue, blocking until something is available. Returns pair of the element found and the length of remaining queue *) let lpop q = let run () = wait_not_empty q; let el = Queue.dequeue_exn q.ev_q in let len = Queue.length q.ev_q in el, len in wrap q run let transfer_queue_in_uncond q in_q = if not (Queue.is_empty in_q) then begin let run () = Queue.transfer ~src:in_q ~dst:q.ev_q in wrap q run end let transfer_queue_in q in_q = if not (Queue.is_empty in_q) then begin let run () = wait_not_full q; Queue.transfer ~src:in_q ~dst:q.ev_q in wrap q run end let transfer_queue_nowait_nolock sq q = Queue.transfer ~src:sq.ev_q ~dst:q let transfer_queue_nowait sq q = if not (Queue.is_empty sq.ev_q) then begin let run () = transfer_queue_nowait_nolock sq q in wrap sq run end let transfer_queue sq q = let run () = wait_not_empty sq; transfer_queue_nowait_nolock sq q in wrap sq run (* The external version of wait_not_empty *) let wait_not_empty sq = let run () = wait_not_empty sq in wrap sq run core-113.00.00/src/squeue.mli000066400000000000000000000045401256461075500155630ustar00rootroot00000000000000(** Thread-safe queue module, using locks. *) open Core_kernel.Std type 'a t with sexp_of (** [create maxsize] returns a synchronized queue bounded to have no more than [maxsize] elements. *) val create : int -> 'a t (** Blocks until there's room on the queue, then pushes. *) val push : 'a t -> 'a -> unit (** Does not block, may grow the queue past maxsize *) val push_uncond : 'a t -> 'a -> unit (** Pushes an event on the queue if the queue is less than maxsize, otherwise drops it. Returns true if the push was successful *) val push_or_drop : 'a t -> 'a -> bool (** returns the number of elements in the queue. *) val length : 'a t -> int (** pops an element off the queue, blocking until something is * available *) val pop : 'a t -> 'a (** returns the element popped and the length of the queue after * this element was popped. *) val lpop : 'a t -> 'a * int (** Transfers all the elements from an ordinary queue into the squeue. Blocks until there's room on the queue, then pushes. may grow queue past maxsize. *) val transfer_queue_in : 'a t -> 'a Linked_queue.t -> unit val transfer_queue_in_uncond : 'a t -> 'a Linked_queue.t -> unit (** Transfers all elements from the squeue to an ordinary queue. The elements remain in order. Waits until at least one element can be transferred. *) val transfer_queue : 'a t -> 'a Linked_queue.t -> unit (** Transfers all elements from the squeue to an ordinary queue. The elements remain in order. Does not wait for elements to arrive. *) val transfer_queue_nowait : 'a t -> 'a Linked_queue.t -> unit (** clears the queue *) val clear : 'a t -> unit (** [wait_not_empty sq] Waits for something to be available. This is useful if you want to wait, but not take something out. This function is not useful in most cases, but in some complex cases it is essential. For example, if you need to take another lock before you remove something from the queue for processing, you might want to try to take that other lock, and if it fails do something else. This function is not dangerous, there is just ONE thing you HAVE to remember if you use it. Just because this function returns doesn't mean that pop will succeed, someone might have gotten there first, so you have to use transfer_queue_nowait if you don't want to block. *) val wait_not_empty : 'a t -> unit core-113.00.00/src/stable.ml000066400000000000000000000007441256461075500153570ustar00rootroot00000000000000include Core_kernel.Stable module Date = Date .Stable module Interval = Interval .Stable module Ofday = Ofday .Stable module Span = Span .Stable module Time = Time .Stable module Time_ns = Time_ns .Stable module Uuid = Uuid .Stable module User_and_group = User_and_group.Stable module Zone = Zone .Stable let _squelch_unused_module_warning_ = () core-113.00.00/src/stable_containers.ml000066400000000000000000000000461256461075500175770ustar00rootroot00000000000000include Core_kernel.Stable_containers core-113.00.00/src/stable_internal.ml000066400000000000000000000000441256461075500172440ustar00rootroot00000000000000include Core_kernel.Stable_internal core-113.00.00/src/stable_unit_test.ml000066400000000000000000000000451256461075500174470ustar00rootroot00000000000000include Core_kernel.Stable_unit_test core-113.00.00/src/stable_unit_test_intf.ml000066400000000000000000000000521256461075500204650ustar00rootroot00000000000000include Core_kernel.Stable_unit_test_intf core-113.00.00/src/staged.ml000066400000000000000000000000331256461075500153430ustar00rootroot00000000000000include Core_kernel.Staged core-113.00.00/src/std.ml000066400000000000000000000027511256461075500146770ustar00rootroot00000000000000include Core_kernel.Std_kernel (* Can't go in Common for circular-reference reasons *) let sec = Time.Span.of_sec let ( ^/ ) = Core_filename.concat module Bigbuffer = Bigbuffer module Bigstring = Bigstring module Bigstring_marshal = Bigstring_marshal module Caml = Caml module Command = Command module Condition = Core_condition module Crc = Crc module Daemon = Daemon module Date = Date module Debug = Debug module Filename = Core_filename module Interval = Interval module Iobuf = Iobuf module Limiter = Limiter module Linux_ext = Linux_ext module Lock_file = Lock_file module Mutex = Core_mutex module Nano_mutex = Nano_mutex module Piecewise_linear = Piecewise_linear module Process_env = Process_env module Signal = Signal module Squeue = Squeue module Sys = Core_sys module Thread = Core_thread module Time = Time module Time_ns = Time_ns module Time_stamp_counter = Time_stamp_counter module Timing_wheel = Timing_wheel_float module Unix = Core_unix module User_and_group = User_and_group module Uuid = Uuid INCLUDE "core_config.mlh" IFDEF BUILD_VERSION_UTIL THEN module Version_util = Version_util ENDIF module Weak_hashtbl = Weak_hashtbl let _squelch_unused_module_warning_ = () core-113.00.00/src/std_common.ml000066400000000000000000000000371256461075500162420ustar00rootroot00000000000000include Core_kernel.Std_common core-113.00.00/src/std_internal.ml000066400000000000000000000000411256461075500165610ustar00rootroot00000000000000include Core_kernel.Std_internal core-113.00.00/src/std_kernel.ml000066400000000000000000000000371256461075500162320ustar00rootroot00000000000000include Core_kernel.Std_kernel core-113.00.00/src/string_id.ml000066400000000000000000000000361256461075500160610ustar00rootroot00000000000000include Core_kernel.String_id core-113.00.00/src/stringable.ml000066400000000000000000000000371256461075500162320ustar00rootroot00000000000000include Core_kernel.Stringable core-113.00.00/src/substring.ml000066400000000000000000000000361256461075500161170ustar00rootroot00000000000000include Core_kernel.Substring core-113.00.00/src/substring_intf.ml000066400000000000000000000000431256461075500171350ustar00rootroot00000000000000include Core_kernel.Substring_intf core-113.00.00/src/syscall_result.ml000066400000000000000000000103121256461075500171450ustar00rootroot00000000000000open Core_kernel.Std type 'a t = int module type S = Syscall_result_intf.S with type 'a syscall_result := 'a t module type Arg = Syscall_result_intf.Arg module Unix = UnixLabels let create_error err = - (Unix_error.to_errno err) module Make (M : Arg) () = struct (* The only reason to have one of these per functor invocation is to make it trivial to get the type right. *) let preallocated_errnos : (_, Unix_error.t) Result.t array = Array.init 64 ~f:(fun i -> Error (Unix_error.of_errno i)) ;; (* Since we return [-errno] from C, we implicitly rely on there not being a 0 [errno]. However, we have 0 in [preallocated_errnos], partly so we can index directly by [errno]. *) TEST "no 0 errno" = preallocated_errnos.(0) = Error (Unix_error.EUNKNOWNERR 0) let num_preallocated_errnos = Array.length preallocated_errnos type nonrec t = M.t t let compare = Int.compare let preallocated_ms = let rec loop i rev_acc = (* Preallocate at most a handful of Ms. 2048 is the first round binary number after 1500, the likely maximum result for many network functions that use [Syscall_result.Int]. *) if i = 2048 then Array.of_list_rev rev_acc else match M.of_int_exn i with | exception _ -> Array.of_list_rev rev_acc | m -> loop (i + 1) (Ok m :: rev_acc) in loop 0 [] ;; let num_preallocated_ms = Array.length preallocated_ms let create_ok x = let t = M.to_int x in if t < 0 then failwithf "Syscall_result.create_ok received negative value (%d)" t () else t ;; let create_error = create_error let is_ok t = t >= 0 let is_error t = t < 0 let to_result t = if is_ok t then if t < num_preallocated_ms then Array.unsafe_get preallocated_ms t else Ok (M.of_int_exn t) else (let errno = -t in if errno < num_preallocated_errnos then Array.unsafe_get preallocated_errnos errno else Error (Unix_error.of_errno errno)) ;; (* We can't use [Core_bench] to do this inside [Core], which it depends on. *) TEST_UNIT "to_result doesn't allocate" = for _i = 1 to 1000 do for t = -(Array.length preallocated_errnos - 1) to Array.length preallocated_ms - 1 do let before_minor = Gc.minor_words () in let before_major = Gc.major_words () in let result = to_result t in let after_minor = Gc.minor_words () in let after_major = Gc.major_words () in <:test_result< int >> ~expect:0 (after_minor - before_minor); <:test_result< int >> ~expect:0 (after_major - before_major); <:test_result< (M.t, Unix_error.t) Result.t >> result ~expect:(if is_ok t then Ok (M.of_int_exn t) else Error (Unix_error.of_errno (-t))); done; done; ;; let sexp_of_t t = <:sexp_of< (M.t, Unix_error.t) Result.t >> (to_result t) let ok_exn t = if is_ok t then M.of_int_exn t else failwiths "Syscall_result.ok_exn received error value" t sexp_of_t ;; let error_code_exn t = if is_ok t then failwiths "Syscall_result.error_code_exn received success value" t sexp_of_t else -t ;; let error_exn t = Unix_error.of_errno (error_code_exn t) let reinterpret_error_exn t = if is_ok t then failwiths "Syscall_result.cast_error_exn received success value" t sexp_of_t else t ;; let ok_or_unix_error_exn t ~syscall_name = if is_ok t then M.of_int_exn t else raise (Unix.Unix_error (Unix_error.of_errno (-t), syscall_name, "")) ;; let ok_or_unix_error_with_args_exn t ~syscall_name x sexp_of_x = if is_ok t then M.of_int_exn t else raise (Unix.Unix_error (Unix_error.of_errno (-t), syscall_name, Sexp.to_string (sexp_of_x x))) ;; end module Int = Make (Int) () module Unit = Make (struct type t = unit with sexp_of, compare let of_int_exn n = assert (n = 0) let to_int () = 0 end) () let unit = Unit.create_ok () let ignore_ok_value t = Core_kernel.Std.Int.min t 0 TEST_UNIT = for i = 1 to 10000 do let err = Unix_error.of_errno i in assert (err = Unit.error_exn (Unit.create_error err)) done; ;; core-113.00.00/src/syscall_result.mli000066400000000000000000000020731256461075500173230ustar00rootroot00000000000000(** Representation of Unix system call results Almost no Unix system call returns a negative integer in case of success. We can use this to encode the result of a system call as either a positive integer value or [-errno]. This allows us to avoid exceptions for dealing with errors such as [EAGAIN]. Indeed, in some context we issue a system call in a tight loop that will often fail with [EAGAIN] and using exceptions to return it is costly. *) open Core_kernel.Std (** There is no [with sexp_of] on purpose as it could only print the ['a] value as an integer. Use [<:sexp_of< Int.t >>] or [<:sexp_of< Unit.t >>]. *) type 'a t = private int (* performance hack *) module type S = Syscall_result_intf.S with type 'a syscall_result := 'a t module type Arg = Syscall_result_intf.Arg module Make (M : Arg) () : S with type ok_value := M.t module Int : S with type ok_value := int module Unit : S with type ok_value := unit val create_error : Unix_error.t -> _ t val unit : Unit.t (** Keep only the error. *) val ignore_ok_value : _ t -> Unit.t core-113.00.00/src/syscall_result_intf.ml000066400000000000000000000021421256461075500201670ustar00rootroot00000000000000open Core_kernel.Std module type S = sig type ok_value type 'a syscall_result type t = ok_value syscall_result with compare, sexp_of val create_ok : ok_value -> t val create_error : Unix_error.t -> t val is_ok : t -> bool val is_error : t -> bool (** This returns a preallocated object for all errors and at least a few [ok_value]s, so can be used in many contexts where avoiding allocation is important. *) val to_result : t -> (ok_value, Unix_error.t) Result.t val ok_exn : t -> ok_value val error_exn : t -> Unix_error.t (** This is more efficient than calling [error_exn] and then the [create_error] of the destination type. *) val reinterpret_error_exn : t -> _ syscall_result val ok_or_unix_error_exn : t -> syscall_name:string -> ok_value val ok_or_unix_error_with_args_exn : t -> syscall_name:string -> 'a -> ('a -> Sexp.t) -> ok_value end module type Arg = sig type t with sexp_of, compare (** [to_int t] must be >= 0, otherwise [create_ok] will raise. *) val to_int : t -> int val of_int_exn : int -> t end core-113.00.00/src/syslog.ml000066400000000000000000000056261256461075500154310ustar00rootroot00000000000000open Core_kernel.Std open Format open Sexplib.Std module Open_option = struct type t = (* THESE MUST STAY IN THE SAME ORDER AS IN syslog_stubs.c!!! *) | PID | CONS | ODELAY | NDELAY | NOWAIT | PERROR with sexp external to_int : t -> int = "core_syslog_open_option_to_int" let collect_mask i t = to_int t lor i let mask ts = Core_list.fold ~f:collect_mask ~init:0 ts end module Facility = struct module T = struct type t = (* THESE MUST STAY IN THE SAME ORDER AS IN syslog_stubs.c!!! *) | KERN | USER | MAIL | DAEMON | AUTH | SYSLOG | LPR | NEWS | UUCP | CRON | AUTHPRIV | FTP | LOCAL0 | LOCAL1 | LOCAL2 | LOCAL3 | LOCAL4 | LOCAL5 | LOCAL6 | LOCAL7 with sexp external to_int : t -> int = "core_syslog_facility_to_int" end include T include Sexpable.To_stringable (T) TEST_UNIT = <:test_result< string >> ~expect:"KERN" (to_string KERN) TEST_UNIT = <:test_result< t >> ~expect:LOCAL7 (of_string "LOCAL7") end module Level = struct module T = struct type t = (* THESE MUST STAY IN THE SAME ORDER AS IN syslog_stubs.c!!! *) | EMERG | ALERT | CRIT | ERR | WARNING | NOTICE | INFO | DEBUG with sexp, enumerate, compare let compare a b = compare b a (* listed in descending order *) TEST_UNIT = <:test_result< int >> ~expect:1 (compare EMERG DEBUG) external to_int : t -> int = "core_syslog_level_to_int" let collect_mask i t = to_int t lor i let mask ts = Core_list.fold ~f:collect_mask ~init:0 ts end include T include Sexpable.To_stringable (T) TEST_UNIT = <:test_result< string >> ~expect:"EMERG" (to_string EMERG) TEST_UNIT = <:test_result< t >> ~expect:DEBUG (of_string "DEBUG") end external core_syslog_openlog : string option -> int -> int -> unit = "core_syslog_openlog" external core_syslog_syslog : int -> string -> unit = "core_syslog_syslog" external core_syslog_closelog : unit -> unit = "core_syslog_closelog" "noalloc" external core_syslog_setlogmask : int -> unit = "core_syslog_setlogmask" "noalloc" let openlog ?id ?(options = []) ?(facility = Facility.USER) () = core_syslog_openlog id (Open_option.mask options) (Facility.to_int facility) let syslog ?(facility = Facility.USER) ?(level = Level.INFO) message = core_syslog_syslog (Level.to_int level lor Facility.to_int facility) message let syslogf ?facility ?level format = ksprintf (fun message -> syslog ?facility ?level message) format let logmask_range ?(to_level = Level.EMERG) from_level = Core_list.fold Level.all ~init:0 ~f:(fun logmask level -> if Level.compare from_level level < 1 && Level.compare level to_level < 1 then Level.to_int level lor logmask else logmask) let setlogmask ?(allowed_levels = []) ?(from_level = Level.DEBUG) ?to_level () = core_syslog_setlogmask (Level.mask allowed_levels lor logmask_range ?to_level from_level) let closelog = core_syslog_closelog core-113.00.00/src/syslog.mli000066400000000000000000000100121256461075500155630ustar00rootroot00000000000000(** Send log messages via the Unix Syslog interface. Syslog is great for system daemons that log free-form human readable status messages or other debugging output, but not so great for archiving structured data. Access to read Syslog's messages may also be restricted. [syslogd]'s logs are also not necessarily kept forever. For application level logging consider {!Core_extended.Std.Logger} instead. *) open Core_kernel.Std module Open_option : sig type t = | PID (** Include PID with each message *) | CONS (** Write directly to system console if there is an error while sending to system logger *) | ODELAY (** Delay opening of the connection until syslog is called *) | NDELAY (** No delay opening connection to syslog daemon *) | NOWAIT (** Do not wait for child processes while logging message *) | PERROR (** Print to stderr as well *) with sexp end (** Types of messages *) module Facility : sig type t = | KERN (** Kernel messages *) | USER (** Generic user-level message (default) *) | MAIL (** Mail subsystem *) | DAEMON (** System daemons without separate facility value *) | AUTH (** Security/authorization messages (DEPRECATED, use AUTHPRIV) *) | SYSLOG (** Messages generated internally by syslogd *) | LPR (** Line printer subsystem *) | NEWS (** USENET news subsystem *) | UUCP (** UUCP subsystem *) | CRON (** Clock daemon (cron and at) *) | AUTHPRIV (** Security/authorization messages (private) *) | FTP (** FTP daemon *) | LOCAL0 | LOCAL1 | LOCAL2 | LOCAL3 | LOCAL4 | LOCAL5 | LOCAL6 | LOCAL7 (** LOCAL0-7 reserved for local use *) with sexp end module Level : sig type t = | EMERG (** System is unusable *) | ALERT (** Action must be taken immediately *) | CRIT (** Critical condition *) | ERR (** Error conditions *) | WARNING (** Warning conditions *) | NOTICE (** Normal, but significant, condition *) | INFO (** Informational message *) | DEBUG (** Debug-level message *) with compare, enumerate, sexp (** [DEBUG] < [EMERG] *) include Stringable.S with type t := t end (** All levels in [allowed_levels] will be allowed, and additionally all ranging from [from_level] to [to_level] (inclusive). *) val setlogmask : ?allowed_levels : Level.t list (** default is {!List.empty} *) -> ?from_level : Level.t (** default is [DEBUG] *) -> ?to_level : Level.t (** default is [EMERG] *) -> unit -> unit (** {2 Logging functions} *) (** [openlog ~id ~options ~facility ()] opens a connection to the system logger (possibly delayed) using prefixed identifier [id], [options], and [facility]. WARNING: this function leaks the [id] argument, if provided. There is no way around that if syslog is called in a multi-threaded environment! Therefore it shouldn't be called too often. What for, anyway? Calling [openlog] before [syslog] is optional. If you forget, syslog will do it for you with the defaults. *) val openlog : ?id : string (** default is [Sys.argv.(0)] *) -> ?options : Open_option.t list (** default is [[ODELAY]] *) -> ?facility : Facility.t (** default is [USER] *) -> unit -> unit (** [syslog ~facility ~level message] logs [message] using syslog with [facility] at [level]. *) val syslog : ?facility : Facility.t (** default is [USER] *) -> ?level : Level.t (** default is [INFO] *) -> string -> unit (** [syslog_printf] acts like [syslog], but allows [printf]-style specification of the message. *) val syslogf : ?facility : Facility.t -> ?level : Level.t -> ('a, unit, string, unit) format4 -> 'a (** [closelog ()] closes the connection to the [syslog] daemon. *) val closelog : unit -> unit core-113.00.00/src/syslog_stubs.c000066400000000000000000000051341256461075500164550ustar00rootroot00000000000000#include #include #include #include #include #include #define Val_none Val_int(0) #define Some_val(v) Field(v, 0) static int log_open_options[] = { /* THESE MUST STAY IN THE SAME ORDER AS IN syslog.ml!!! */ LOG_PID, LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT, LOG_PERROR }; CAMLprim value core_syslog_open_option_to_int(value v_open_option) { return Val_int(log_open_options[Int_val(v_open_option)]); } static int log_facilities[] = { /* THESE MUST STAY IN THE SAME ORDER AS IN syslog.ml!!! */ LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS, LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP, LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 }; CAMLprim value core_syslog_facility_to_int(value v_facility) { return Val_int(log_facilities[Int_val(v_facility)]); } static int log_levels[] = { /* THESE MUST STAY IN THE SAME ORDER AS IN syslog.ml!!! */ LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG }; CAMLprim value core_syslog_level_to_int(value v_level) { return Val_int(log_levels[Int_val(v_level)]); } /* XXX: WARNING: this function leaks memory if v_ident is not None! No way around that if syslog is called in a multi-threaded environment! Therefore it shouldn't be called too often. What for, anyway? */ CAMLprim value core_syslog_openlog(value v_ident, value v_open_option, value v_facility) { char *ident = NULL; /* default to argv[0], as per syslog(3) */ if (v_ident != Val_none) { int len = caml_string_length(Some_val(v_ident)) + 1; ident = caml_stat_alloc(len); memcpy(ident, String_val(Some_val(v_ident)), len); } caml_enter_blocking_section(); openlog(ident, Int_val(v_open_option), Int_val(v_facility)); /* openlog doesn't inter ident (if specified), so freeing it here would create an invalid program. */ caml_leave_blocking_section(); return Val_unit; } /* A priority is a level | facility. See syslog(3). */ CAMLprim value core_syslog_syslog(value v_priority, value v_message) { int len = caml_string_length(v_message) + 1; char *message = caml_stat_alloc(len); memcpy(message, String_val(v_message), len); caml_enter_blocking_section(); syslog(Int_val(v_priority), "%s", message); free(message); caml_leave_blocking_section(); return Val_unit; } CAMLprim value core_syslog_closelog() { closelog(); return Val_unit; } CAMLprim value core_syslog_setlogmask(value v_mask) { setlogmask(Int_val(v_mask)); return Val_unit; } core-113.00.00/src/t.ml000066400000000000000000000000261256461075500143410ustar00rootroot00000000000000include Core_kernel.T core-113.00.00/src/thread_safe_queue_unit_tests.ml000066400000000000000000000076311256461075500220410ustar00rootroot00000000000000open Core_kernel.Std TEST_MODULE "Thread_safe_queue" = (struct let () = Debug.should_print_backtrace := false open Thread_safe_queue type nonrec 'a t = 'a t let invariant = invariant let sexp_of_t = sexp_of_t TEST_UNIT = ignore (create () |> <:sexp_of< unit t >> : Sexp.t) TEST_UNIT = let t = create () in enqueue t 1; enqueue t 2; enqueue t 3; ignore (t |> <:sexp_of< int t >> : Sexp.t); ;; let create = create let dequeue_exn = dequeue_exn let enqueue = enqueue let length = length TEST_UNIT = let t = create () in invariant ignore t; assert (length t = 0); enqueue t (); invariant ignore t; assert (length t = 1); enqueue t (); invariant ignore t; assert (length t = 2); dequeue_exn t; invariant ignore t; assert (length t = 1); dequeue_exn t; invariant ignore t; assert (length t = 0); ;; TEST_UNIT = (* invariant passes with element from pool in the queue *) let t = create () in for _i = 1 to 3 do enqueue t (); done; for _i = 1 to 2 do dequeue_exn t; done; enqueue t (); invariant ignore t; ;; TEST_UNIT = let verbose = false in let sec = Time.Span.of_sec in let quick_pause () = Time.pause (sec 0.00001) in let num_elts = 100_000 in let batch_size = 10_000 in for num_enqueuers = 1 to 1 do for num_dequeuers = 1 to 1 do if verbose then Debug.eprints "testing" (num_enqueuers, num_dequeuers) <:sexp_of< int * int >>; let enqueue_counts = Array.create ~len:num_enqueuers 0 in let dequeue_counts = Array.create ~len:num_dequeuers 0 in let t = create () in let all_threads = ref [] in let create_thread f = let thread = Thread.create f () in all_threads := thread :: !all_threads; in let num_enqueues = ref 0 in let num_dequeues = ref 0 in create_thread (fun () -> while !num_enqueues < num_elts || !num_dequeues < num_elts do if verbose then Debug.eprints "current" (!num_enqueues, !num_dequeues) <:sexp_of< int * int >>; Time.pause (sec 1.); done); for i = 0 to num_enqueuers - 1 do create_thread (fun () -> let num_in_batch = ref 0 in while !num_enqueues < num_elts do num_in_batch := 0; while !num_enqueues < num_elts && !num_in_batch < batch_size do incr num_in_batch; incr num_enqueues; enqueue_counts.( i ) <- enqueue_counts.( i ) + 1; enqueue t (); done; quick_pause (); done); done; for i = 0 to num_dequeuers - 1 do create_thread (fun () -> let num_in_batch = ref 0 in while !num_dequeues < num_elts do num_in_batch := 0; while !num_dequeues < num_elts && !num_in_batch < batch_size do if length t = 0 then quick_pause () else begin dequeue_exn t; incr num_dequeues; dequeue_counts.( i ) <- dequeue_counts.( i ) + 1; end; done; done); done; List.iter !all_threads ~f:Thread.join; if verbose then Debug.eprints "counts" (enqueue_counts, dequeue_counts) <:sexp_of< int array * int array >>; done; done; ;; let clear_internal_pool = clear_internal_pool TEST_UNIT = let t = create () in clear_internal_pool t; enqueue t (); clear_internal_pool t; dequeue_exn t; clear_internal_pool t; enqueue t (); clear_internal_pool t; ;; end (* This signature constraint is here to remind us to add a unit test whenever the interface to [Thread_safe_queue] changes. *) : module type of Thread_safe_queue) core-113.00.00/src/thread_safe_queue_unit_tests.mli000066400000000000000000000000551256461075500222030ustar00rootroot00000000000000(** This signature is deliberately empty. *) core-113.00.00/src/time.ml000066400000000000000000000020241256461075500150340ustar00rootroot00000000000000open Core_kernel.Std module Zone = Zone module Span = Span module Ofday = struct include (Ofday : (module type of Ofday with type t = Ofday.t with module Zoned := Ofday.Zoned)) module Zoned = struct include Ofday.Zoned let to_time t date = Time0.of_date_ofday ~zone:(zone t) date (ofday t) end (* can't be defined in Ofday directly because it would create a circular reference *) let now ~zone = Time0.to_ofday ~zone (Time0.now ()) end include Time0 BENCH_MODULE "Time" = struct BENCH_FUN "Time.to_string" = let t = of_float 100000.99999999999 in (fun () -> ignore (to_string t)) BENCH_FUN "Time.to_ofday" = let t = now () in (fun () -> ignore (to_ofday t ~zone:Zone.local)) BENCH "Time.now" = now () let x = Float.of_string "1.1" BENCH "Time.Span.of_hr" = Span.of_hr x BENCH "Time.Span.of_min" = Span.of_min x BENCH "Time.Span.of_sec" = Span.of_sec x BENCH "Time.Span.of_ms" = Span.of_ms x BENCH "Time.Span.of_ns" = Span.of_ns x end core-113.00.00/src/time.mli000066400000000000000000000213551256461075500152150ustar00rootroot00000000000000(** A module for representing absolute points in time, independent of time zone. *) open Core_kernel.Std module Ofday : sig include (module type of Ofday with type t = Ofday.t with module Zoned := Ofday.Zoned) module Zoned : sig include module type of Ofday.Zoned val to_time : t -> Date0.t -> Time_internal.T.t end val now : zone:Zone.t -> t end module Span : sig include (module type of Span with type t = Span.t with module Parts := Span.Parts) module Parts : sig type t = Span.Parts.t = private { sign : Float.Sign.t; hr : int; min : int; sec : int; ms : int; us : int; } with sexp end end module Zone : module type of Zone with type t = Zone.t (** A fully qualified point in time, independent of timezone. *) type t = Time_internal.T.t with bin_io, sexp (** Sexp conversions use the local timezone by default. This can be overridden by calling [set_sexp_zone]. *) val get_sexp_zone : unit -> Zone.t val set_sexp_zone : Zone.t -> unit include Hashable_binable with type t := t include Comparable_binable with type t := t include Robustly_comparable with type t := t include Floatable with type t := t include Pretty_printer.S with type t := t (** The [{to,of}_string] functions in [Time] will produce times with time zone indications, but are generous in what they will read in. String/Sexp.t representations without time zone indications are assumed to be in the machine's local zone. *) include Stringable with type t := t (** {5 values} *) (** Unlike [Time_ns], this module purposely omits [max_value] and [min_value]: 1. They produce unintuitive corner cases because most people's mental models of time do not include +/- infinity as concrete values 2. In practice, when people ask for these values, it is for questionable uses, e.g., as null values to use in place of explicit options. *) (** midnight, Jan 1, 1970 in UTC *) val epoch : t (** {6 Basic operations on times} *) (** [add t s] adds the span [s] to time [t] and returns the resulting time. NOTE: adding spans as a means of adding days is not accurate, and may run into trouble due to shifts in daylight savings time, float arithmetic issues, and leap seconds. See the comment at the top of Zone.mli for a more complete discussion of some of the issues of time-keeping. For spans that cross date boundaries, use date functions instead. *) val add : t -> Span.t -> t (** [sub t s] subtracts the span [s] from time [t] and returns the resulting time. See important note for [add]. *) val sub : t -> Span.t -> t (** [diff t1 t2] returns time [t1] minus time [t2]. *) val diff : t -> t -> Span.t (** [abs_diff t1 t2] returns the absolute span of time [t1] minus time [t2]. *) val abs_diff : t -> t -> Span.t (** {6 Comparisons} *) (** [is_earlier] and [is_later] are like using [<.], but easier to read. *) val is_earlier : t -> than:t -> bool val is_later : t -> than:t -> bool (** {6 Constants} *) (** {6 Conversions} *) (** All these conversion functions use the current time zone. Unless marked _utc, in which case they use Universal Coordinated Time *) val of_date_ofday : Date0.t -> Ofday.t -> zone:Zone.t -> t val to_date_ofday : t -> zone:Zone.t -> Date0.t * Ofday.t val to_date : t -> zone:Zone.t -> Date0.t val to_ofday : t -> zone:Zone.t -> Ofday.t (** Because timezone offsets change throughout the year (clocks go forward or back) some local times can occur twice or not at all. In the case that they occur twice, this function gives [`Twice] with both occurrences in order; if they do not occur at all, this function gives [`Never] with the time at which the local clock skips over the desired time of day. Note that this is really only intended to work with DST transitions and not unusual or dramatic changes, like the calendar change in 1752 (run "cal 9 1752" in a shell to see). In particular it makes the assumption that midnight of each day is unambiguous. Most callers should use {!of_date_ofday} rather than this function. In the [`Twice] and [`Never] cases, {!of_date_ofday} will return reasonable times for most uses. *) val of_date_ofday_precise : Date0.t -> Ofday.t -> zone:Zone.t -> [ `Once of t | `Twice of t * t | `Never of t ] val convert : from_tz:Zone.t -> to_tz:Zone.t -> Date0.t -> Ofday.t -> (Date0.t * Ofday.t) val utc_offset : t -> zone:Zone.t -> Span.t (** {6 Other string conversions} *) (** [to_filename_string t ~zone] converts [t] to string with format YYYY-MM-DD_HH-MM-SS.mmm which is suitable for using in filenames. *) val to_filename_string : t -> zone:Zone.t -> string (** [of_filename_string s ~zone] converts [s] that has format YYYY-MM-DD_HH-MM-SS.mmm into time. *) val of_filename_string : string -> zone:Zone.t -> t val to_string_fix_proto : [`Utc | `Local] -> t -> string val of_string_fix_proto : [`Utc | `Local] -> string -> t (** Same as [to_string_abs], but removes trailing seconds and milliseconds if they are 0 *) val to_string_trimmed : t -> zone:Zone.t -> string (** Same as [to_string_abs], but without milliseconds *) val to_sec_string : t -> zone:Zone.t -> string (** [of_localized_string ~zone str] read in the given string assuming that it represents a time in zone and return the appropriate Time.t *) val of_localized_string : zone:Zone.t -> string -> t (** [to_string_abs ~zone t] returns a string that represents an absolute time, rather than a local time with an assumed time zone. This string can be round-tripped, even on a machine in a different time zone than the machine that wrote the string. The string will display the date and of-day of [zone] together with [zone] as an offset from UTC. [to_string_abs_trimmed] is the same as [to_string_abs], but drops trailing seconds and milliseconds if they are 0. Note that the difference between [to_string] and [to_string_abs] is not that one returns an absolute time and one doesn't, but that [to_string_abs] lets you specify the time zone, while [to_string] takes it to be the local time zone. *) val to_string_abs : t -> zone:Zone.t -> string val to_string_abs_trimmed : t -> zone:Zone.t -> string (** [of_string_abs s] is like [of_string], but demands that [s] indicate the timezone the time is expressed in. *) val of_string_abs : string -> t (** [t_of_sexp_abs sexp] as [t_of_sexp], but demands that [sexp] indicate the timezone the time is expressed in. *) val t_of_sexp_abs : Sexp.t -> t (** {6 Miscellaneous} *) (** @return the current time. *) val now : unit -> t (** [pause span] sleeps for span time. *) val pause : Span.t -> unit (** [interruptible_pause span] sleeps for span time unless interrupted (e.g. by delivery of a signal), in which case the remaining unslept portion of time is returned. *) val interruptible_pause : Span.t -> [`Ok | `Remaining of Span.t] (** [pause_forever] sleeps indefinitely. *) val pause_forever : unit -> never_returns (** [occurrence side time ~ofday ~zone] returns a [Time.t] that is the occurrence of ofday (in the given [zone]) that is the latest occurrence (<=) [time] or the earliest occurrence (>=) [time], according to [side]. NOTE: If the given time converted to wall clock time in the given zone is equal to ofday then the t returned will be equal to the t given. *) val occurrence : [ `First_after_or_at | `Last_before_or_at ] -> t -> ofday:Ofday.t -> zone:Zone.t -> t (** [format t fmt] formats the given time according to fmt, which follows the formatting rules given in 'man strftime'. The time is output in the local timezone. {v %Y - year (4 digits) %y - year (2 digits) %m - month %d - day %H - hour %M - minute %S - second v} a common choice would be: %Y-%m-%d %H:%M:%S *) val format : t -> string -> string (** [to_epoch t] returns the number of seconds since Jan 1, 1970 00:00:00 in UTC *) val to_epoch : t -> float (* [next_multiple ~base ~after ~interval] returns the smallest [time] of the form: {[ time = base + k * interval ]} where [k >= 0] and [time > after]. It is an error if [interval <= 0]. Supplying [~can_equal_after:true] allows the result to satisfy [time >= after]. *) val next_multiple : ?can_equal_after:bool (** default is [false] *) -> base:t -> after:t -> interval:Span.t -> unit -> t module Stable : sig module V1 : sig type t with bin_io, sexp, compare end with type t = t (** Provides a sexp representation that is independent of the time zone of the machine writing it. *) module With_utc_sexp : sig module V1 : sig type t with bin_io, sexp, compare end with type t = t end end core-113.00.00/src/time0.ml000066400000000000000000000506461256461075500151310ustar00rootroot00000000000000open Core_kernel.Std module Date = Date0 module Unix = Core_unix module Stable = struct module V1 = struct (* IF THIS REPRESENTATION EVER CHANGES, ENSURE THAT EITHER (1) all values serialize the same way in both representations, or (2) you add a new Time version to stable.ml *) include Time_internal let to_epoch t = T.to_float t module Epoch_cache = struct type t = { zone : Zone.t; day_start : float; day_end : float; date : Date.t } with sexp end let of_epoch_internal zone time (* shifted epoch for the time zone for conversion *) = let parts = Float.modf time in let sec = Float.Parts.integral parts in let subsec = Float.Parts.fractional parts in let sec,subsec = if subsec < 0. then (sec -. 1., 1. +. subsec) else (sec, subsec) in let tm = Unix.gmtime sec in let date = Date.of_tm tm in let ofday_span = Float.of_int (tm.Unix.tm_hour * 60 * 60 + tm.Unix.tm_min * 60 + tm.Unix.tm_sec) +. (Float.abs subsec) in let ofday = Ofday.of_span_since_start_of_day (Span.of_sec ofday_span) in let day_start = time -. ofday_span in let day_end = day_start +. (24. *. 60. *. 60.) in let cache = {Epoch_cache. zone; day_start; day_end; date } in (cache, (date, ofday)) ;; (* A thin caching layer over the actual of_epoch (of_epoch_internal just above) used only to gain some speed when we translate the same time/date over and over again *) let of_epoch = let cache = ref (fst (of_epoch_internal Zone.utc (to_epoch (T.now ())))) in (fun zone unshifted -> let time = Zone.shift_epoch_time zone `UTC unshifted in let {Epoch_cache.zone = z; day_start = s; day_end = e; date = date} = !cache in if phys_equal zone z && time >= s && time < e then ( (date, Ofday.of_span_since_start_of_day (Span.of_sec (time -. s)))) else begin let (new_cache,r) = of_epoch_internal zone time in cache := new_cache; r end) ;; let to_date_ofday time ~zone = try of_epoch zone (to_epoch time) with | Unix.Unix_error(_, "gmtime", _) -> raise (Invalid_argument "Time.to_date_ofday") ;; let of_date_ofday date ofday ~zone = let time = let epoch = utc_mktime ~year:(Date.year date) ~month:(Month.to_int (Date.month date)) ~day:(Date.day date) ~ofday_sec:(Span.to_sec (Ofday.to_span_since_start_of_day ofday)) in Zone.shift_epoch_time zone `Local epoch in T.of_float time ;; let of_date_ofday_precise date ofday ~zone = (* We assume that there will be only one zone shift within a given local day. *) let start_of_day = of_date_ofday ~zone date Ofday.start_of_day in let proposed_time = T.add start_of_day (Ofday.to_span_since_start_of_day ofday) in match Zone.next_clock_shift zone ~after:start_of_day with | None -> `Once proposed_time | Some (shift_start, shift_amount) -> let shift_backwards = Span.(shift_amount < zero) in (* start and end of the "problematic region" *) let s,e = if shift_backwards then T.add shift_start shift_amount, shift_start else shift_start, T.add shift_start shift_amount in if T.(proposed_time < s) then `Once proposed_time else if T.(s <= proposed_time && proposed_time < e) then begin if shift_backwards then `Twice (proposed_time, T.sub proposed_time shift_amount) else `Never shift_start end else `Once (T.sub proposed_time shift_amount) ;; TEST_MODULE = struct let ldn = Zone.find_exn "Europe/London" ;; let mkt month day hr min = let ofday_mins = ((Float.of_int hr *. 60.) +. (Float.of_int min)) in let ofday_sec = ofday_mins *. 60. in utc_mktime ~year:2013 ~month ~day ~ofday_sec ;; let expect_once date ofday expected = match of_date_ofday_precise ~zone:ldn date ofday with | `Once t -> T.(t = of_float expected) | _ -> false ;; let expect_never date ofday expected = match of_date_ofday_precise ~zone:ldn date ofday with | `Never t -> T.(t = of_float expected) | _ -> false ;; let expect_twice date ofday expected1 expected2 = match of_date_ofday_precise ~zone:ldn date ofday with | `Twice (t1, t2) -> T.(t1 = of_float expected1 && t2 = of_float expected2) | _ -> false ;; let outside_bst = Date.of_string "2013-01-01";; let inside_bst = Date.of_string "2013-06-01";; let midday = Ofday.of_string "12:00";; TEST "of_date_ofday_precise, outside BST" = expect_once outside_bst midday (mkt 01 01 12 00) ;; TEST "of_date_ofday_precise, inside BST" = expect_once inside_bst midday (mkt 06 01 11 00) ;; let bst_start = Date.of_string "2013-03-31";; let bst_end = Date.of_string "2013-10-27";; let just_before = Ofday.of_string "00:59";; let start_time = Ofday.of_string "01:00";; let during = Ofday.of_string "01:30";; let end_time = Ofday.of_string "02:00";; let just_after = Ofday.of_string "02:01";; TEST "of_date_ofday_precise, BST start, just_before" = expect_once bst_start just_before (mkt 03 31 00 59) ;; TEST "of_date_ofday_precise, BST start, start_time" = expect_never bst_start start_time (mkt 03 31 01 00) ;; TEST "of_date_ofday_precise, BST start, during" = expect_never bst_start during (mkt 03 31 01 00) ;; TEST "of_date_ofday_precise, BST start, end_time" = expect_once bst_start end_time (mkt 03 31 01 00) ;; TEST "of_date_ofday_precise, BST start, just_after" = expect_once bst_start just_after (mkt 03 31 01 01) ;; TEST "of_date_ofday_precise, BST end, just_before" = expect_once bst_end just_before (mkt 10 26 23 59) ;; TEST "of_date_ofday_precise, BST end, start_time" = expect_twice bst_end start_time (mkt 10 27 00 00) (mkt 10 27 01 00) ;; TEST "of_date_ofday_precise, BST end, during" = expect_twice bst_end during (mkt 10 27 00 30) (mkt 10 27 01 30) ;; TEST "of_date_ofday_precise, BST end, end_time" = expect_once bst_end end_time (mkt 10 27 02 00) ;; TEST "of_date_ofday_precise, BST end, just_after" = expect_once bst_end just_after (mkt 10 27 02 01) ;; end let to_date t ~zone = fst (to_date_ofday t ~zone) let to_ofday t ~zone = snd (to_date_ofday t ~zone) let convert ~from_tz ~to_tz date ofday = let start_time = T.to_float (of_date_ofday ~zone:from_tz date ofday) in of_epoch to_tz start_time let utc_offset t ~zone = let epoch = to_epoch t in let utc_epoch = Zone.shift_epoch_time zone `UTC epoch in Span.of_sec (utc_epoch -. epoch) ;; let offset_string time ~zone = let utc_offset = utc_offset time ~zone in let is_utc = Span.(=) utc_offset Span.zero in if is_utc then "Z" else String.concat [ (if Span.(<) utc_offset Span.zero then "-" else "+"); Ofday.to_string_trimmed (Ofday.of_span_since_start_of_day (Span.abs utc_offset)); ] ;; let to_string_abs_parts time ~zone = let date, ofday = to_date_ofday time ~zone in let offset_string = offset_string time ~zone in [ Date.to_string date; String.concat ~sep:"" [ Ofday.to_string ofday; offset_string ] ] ;; let to_string_abs_trimmed time ~zone = let date, ofday = to_date_ofday time ~zone in let offset_string = offset_string time ~zone in String.concat ~sep:" " [ (Date.to_string date) ; (Ofday.to_string_trimmed ofday) ^ offset_string ] ;; let to_string_abs time ~zone = String.concat ~sep:" " (to_string_abs_parts ~zone time) ;; let to_string_trimmed t ~zone = let date, sec = to_date_ofday ~zone t in (Date.to_string date) ^ " " ^ (Ofday.to_string_trimmed sec) ;; let to_sec_string t ~zone = let date, sec = to_date_ofday ~zone t in (Date.to_string date) ^ " " ^ (Ofday.to_sec_string sec) ;; let to_filename_string t ~zone = let date, ofday = to_date_ofday ~zone t in (Date.to_string date) ^ "_" ^ (String.tr ~target:':' ~replacement:'-' (Ofday.to_string ofday)) ;; let to_string_fix_proto utc t = let zone = match utc with | `Utc -> Zone.utc | `Local -> Zone.local in let date, sec = to_date_ofday t ~zone in (Date.to_string_iso8601_basic date) ^ "-" ^ (Ofday.to_millisec_string sec) ;; let of_string_fix_proto utc str = try let expect_length = 21 in (* = 8 + 1 + 12 *) let expect_dash = 8 in if str.[expect_dash] <> '-' then failwithf "no dash in position %d" expect_dash (); let zone = match utc with | `Utc -> Zone.utc | `Local -> Zone.local in if Int.(>) (String.length str) expect_length then failwithf "input too long" (); of_date_ofday ~zone (Date.of_string_iso8601_basic str ~pos:0) (Ofday.of_string_iso8601_extended str ~pos:(expect_dash + 1)) with exn -> invalid_argf "Time.of_string_fix_proto %s: %s" str (Exn.to_string exn) () ;; let of_filename_string s ~zone = try match String.lsplit2 s ~on:'_' with | None -> failwith "no space in filename string" | Some (date, ofday) -> let date = Date.of_string date in let ofday = String.tr ~target:'-' ~replacement:':' ofday in let ofday = Ofday.of_string ofday in of_date_ofday date ofday ~zone with | exn -> invalid_argf "Time.of_filename_string (%s): %s" s (Exn.to_string exn) () ;; let format t s = Unix.strftime (to_tm t) s let pause_for span = let time_remaining = (* If too large a float is passed in (Span.max_value for instance) then nanosleep will return immediately, leading to an infinite and expensive select loop. This is handled by pausing for no longer than 100 days. *) let span = Span.min span (Span.scale Span.day 100.) in Unix.nanosleep (Span.to_sec span) in if time_remaining > 0.0 then `Remaining (Span.of_sec time_remaining) else `Ok ;; (** Pause and don't allow events to interrupt. *) let rec pause span = match pause_for span with | `Remaining span -> pause span | `Ok -> () ;; (** Pause but allow events to interrupt. *) let interruptible_pause = pause_for let rec pause_forever () = pause (Span.of_day 1.0); pause_forever () ;; let occurrence before_or_after t ~ofday ~zone = let first_guess_date = to_date t ~zone in let first_guess = of_date_ofday ~zone first_guess_date ofday in let cmp, increment = match before_or_after with | `Last_before_or_at -> T.(<=), (-1) | `First_after_or_at -> T.(>=), 1 in if cmp first_guess t then first_guess else of_date_ofday ~zone (Date.add_days first_guess_date increment) ofday ;; let epoch = T.of_float 0.0 (* There are a number of things that would be shadowed by this include because of the scope of Constrained_float. These need to be defined below. It's a an unfortunate situation because we would like to say include T, without shadowing. *) include T let to_string t = to_string_abs t ~zone:Zone.local exception Time_of_string of string * Exn.t with sexp exception Time_string_not_absolute of string with sexp let of_string_gen ~require_absolute s = try let date,ofday,tz = match String.split s ~on:' ' with | [day; month; year; ofday] -> (String.concat [day; " "; month; " "; year], ofday, None) | [date; ofday; tz] -> (date, ofday, Some tz) | [date; ofday] -> (date, ofday, None) | [s] -> begin match String.rsplit2 ~on:'T' s with | Some (date, ofday) -> (date, ofday, None) | None -> failwith "no spaces or T found" end | _ -> failwith "too many spaces" in let ofday_to_sec od = Span.to_sec (Ofday.to_span_since_start_of_day od) in let ofday,utc_offset = match tz with | Some _ -> ofday, None | None -> if Char.(=) ofday.[String.length ofday - 1] 'Z' then (String.sub ofday ~pos:0 ~len:(String.length ofday - 1)), Some 0. else begin match String.lsplit2 ~on:'+' ofday with | Some (l,r) -> assert (Char.(=) r.[1] ':' || Char.(=) r.[2] ':'); l, Some (ofday_to_sec (Ofday.of_string r)) | None -> match String.lsplit2 ~on:'-' ofday with | Some (l,r) -> assert (Char.(=) r.[1] ':' || Char.(=) r.[2] ':'); l, Some ((-1.) *. (ofday_to_sec (Ofday.of_string r))) | None -> ofday, None end in let date = Date.of_string date in let ofday = Ofday.of_string ofday in match tz with | Some tz -> of_date_ofday ~zone:(Zone.find_exn tz) date ofday | None -> match utc_offset with | None -> if require_absolute then raise (Time_string_not_absolute s); of_date_ofday ~zone:Zone.local date ofday | Some utc_offset -> of_float (to_float (of_date_ofday ~zone:Zone.utc date ofday) -. utc_offset) with | e -> raise (Time_of_string (s,e)) ;; let of_string_abs s = of_string_gen ~require_absolute:true s let of_string s = of_string_gen ~require_absolute:false s let t_of_sexp_gen sexp of_string = try match sexp with | Sexp.List [Sexp.Atom date; Sexp.Atom ofday; Sexp.Atom tz] -> of_date_ofday ~zone:(Zone.find_exn tz) (Date.of_string date) (Ofday.of_string ofday) | Sexp.List [Sexp.Atom date; Sexp.Atom ofday] -> of_string (date ^ " " ^ ofday) | Sexp.Atom datetime -> of_string datetime | _ -> of_sexp_error "Time.t_of_sexp" sexp with | Of_sexp_error _ as e -> raise e | e -> of_sexp_error (sprintf "Time.t_of_sexp: %s" (Exn.to_string e)) sexp ;; let t_of_sexp sexp = t_of_sexp_gen sexp of_string let t_of_sexp_abs sexp = t_of_sexp_gen sexp of_string_abs let sexp_of_t_abs ~zone t = Sexp.List (List.map (to_string_abs_parts ~zone t) ~f:(fun s -> Sexp.Atom s)) ;; let sexp_zone = ref Zone.local let get_sexp_zone () = !sexp_zone let set_sexp_zone zone = sexp_zone := zone let sexp_of_t t = sexp_of_t_abs ~zone:!sexp_zone t module C = struct type t = T.t with bin_io let compare = compare type comparator_witness = T.comparator_witness let comparator = T.comparator (* In 108.06a and earlier, times in sexps of Maps and Sets were raw floats. From 108.07 through 109.13, the output format remained raw as before, but both the raw and pretty format were accepted as input. From 109.14 on, the output format was changed from raw to pretty, while continuing to accept both formats. Once we believe most programs are beyond 109.14, we will switch the input format to no longer accept raw. *) let sexp_of_t = sexp_of_t let t_of_sexp sexp = match Option.try_with (fun () -> T.of_float (Float.t_of_sexp sexp)) with | Some t -> t | None -> t_of_sexp sexp ;; end let is_earlier t1 ~than:t2 = t1 <. t2 let is_later t1 ~than:t2 = t1 >. t2 module Map = Map.Make_binable_using_comparator (C) module Set = Set.Make_binable_using_comparator (C) TEST = Set.equal (Set.of_list [epoch]) (Set.t_of_sexp (Sexp.List [Float.sexp_of_t (to_float epoch)])) ;; include Pretty_printer.Register (struct type nonrec t = t let to_string = to_string let module_name = "Core.Std.Time" end) let of_localized_string ~zone str = try match String.lsplit2 str ~on:' ' with | None -> invalid_arg (sprintf "no space in date_ofday string: %s" str) | Some (date,time) -> let date = Date.of_string date in let ofday = Ofday.of_string time in of_date_ofday ~zone date ofday with e -> Exn.reraise e "Time.of_localstring" ;; let next_multiple ?(can_equal_after = false) ~base ~after ~interval () = if Span.(<=) interval Span.zero then failwiths "Time.next_multiple got nonpositive interval" interval <:sexp_of< Span.t >>; let base_to_after = diff after base in if Span.(<) base_to_after Span.zero then base (* [after < base], choose [k = 0]. *) else begin let next = add base (Span.scale interval (Float.round ~dir:`Down (Span.(//) base_to_after interval))) in if next > after || (can_equal_after && next = after) then next else add next interval end ;; TEST_UNIT = let expected_next_multiple ~base ~after ~interval = let rec loop at = if (>) at after then at else loop (add at interval) in loop base in List.iter ~f:(fun (since_base, interval) -> let base = epoch in let sec = Span.of_sec in let interval = sec interval in let after = add base (sec since_base) in let actual_next_multiple = next_multiple ~base ~after ~interval () in let expected_next_multiple = expected_next_multiple ~base ~after ~interval in let relativize time = diff time base in let times_are_close t1 t2 = Float.(<) (Float.abs (Span.to_us (diff t1 t2))) 1. in if not (times_are_close actual_next_multiple expected_next_multiple) then failwiths "Time.next_multiple" (since_base, interval, relativize expected_next_multiple, relativize actual_next_multiple) (<:sexp_of< float * Span.t * Span.t * Span.t >>)) [ 0. , 1.; 0.1 , 1.; 0.9 , 1.; 1. , 1.; 1.1 , 1.; 1.9 , 1.; 1000.1, 1.; (-1.) , 1.; (-1.) , 0.1; 1. , 0.2; 1E-5 , 1E-6; ] ;; end TEST_MODULE "Time.V1" = struct TEST_MODULE "Time.V1 functor application" = Core_kernel.Stable_unit_test.Make (struct include V1 let zone = Zone.find_exn "America/New_York" let sexp_of_t t = sexp_of_t_abs ~zone t let tests = let time ~y ~m ~d ofday = of_date_ofday ~zone (Date.create_exn ~y ~m ~d) ofday in [ time ~y:2012 ~m:Month.Apr ~d:9 (Ofday.create ~hr:12 ()), "(2012-04-09 12:00:00.000000-04:00)", "\000\000\000\224\193\224\211\065"; time ~y:1985 ~m:Month.Jun ~d:5 (Ofday.create ~hr:5 ~min:25 ()), "(1985-06-05 05:25:00.000000-04:00)", "\000\000\000\108\039\004\189\065"; ] @ if Int.(Core_sys.c_int_size () < 64) then [] else [ time ~y:2222 ~m:Month.Nov ~d:22 (Ofday.create ~hr:17 ~min:17 ~sec:17 ()), "(2222-11-22 17:17:17.000000-05:00)", "\000\000\208\230\204\186\253\065"; ] end) (* test that t_of_sexp accepts sexps qualified with time zones in two formats *) TEST_UNIT = ignore (V1.t_of_sexp (Sexp.of_string "(2012-04-09 12:00:00.000000-04:00:00)")) TEST_UNIT = ignore (V1.t_of_sexp (Sexp.of_string "(2012-04-09 12:00:00.000000 America/New_York)")) end module With_utc_sexp = struct module V1 = struct include V1 let sexp_of_t t = sexp_of_t_abs t ~zone:Zone.utc end end end include Stable.V1 TEST_MODULE "Time robustly compare" = struct TEST = of_float 0.0 =. of_float 0.000_000_99 TEST = of_float 0.0 <. of_float 0.000_001_1 TEST_UNIT = for i = 0 to 100 do let time = of_float (Float.of_int i /. 17.) in assert ((=.) time (sexp_of_t time |! t_of_sexp)) done end core-113.00.00/src/time_internal.ml000066400000000000000000000103421256461075500167320ustar00rootroot00000000000000INCLUDE "core_config.mlh" open Core_kernel.Std module Helpers = struct let char_of_digit n = Char.unsafe_of_int (Char.to_int '0' + n) let invalid_range ~digits ~max ~i = invalid_argf "Time.string_of_int_%d_digits: argument must be (0, %d) %d" digits max i () ;; let blit_string_of_int_4_digits s ~pos i = if i >= 10000 || i < 0 then invalid_range ~digits:4 ~max:9999 ~i; let j = i / 10 in s.[pos + 3] <- char_of_digit (i - j * 10); let k = j / 10 in s.[pos + 2] <- char_of_digit (j - k * 10); let l = k / 10 in s.[pos + 1] <- char_of_digit (k - l * 10); s.[pos ] <- char_of_digit l; ;; TEST_UNIT = for i = 0 to 9999 do let s = String.make 4 ' ' in blit_string_of_int_4_digits s ~pos:0 i; <:test_result< string >> ~expect:(Printf.sprintf "%04d" i) s done ;; let blit_string_of_int_2_digits s ~pos i = if i >= 100 || i < 0 then invalid_range ~digits:4 ~max:99 ~i; let j = i / 10 in s.[pos + 1] <- char_of_digit (i - j * 10); s.[pos ] <- char_of_digit j; ;; TEST_UNIT = for i = 0 to 99 do let s = String.make 2 ' ' in blit_string_of_int_2_digits s ~pos:0 i; <:test_result< string >> ~expect:(Printf.sprintf "%02d" i) s done ;; let blit_string_of_int_3_digits s ~pos i = if i >= 1000 || i < 0 then invalid_range ~digits:4 ~max:999 ~i; let j = i / 10 in s.[pos + 2] <- char_of_digit (i - j * 10); let k = j / 10 in s.[pos + 1] <- char_of_digit (j - k * 10); s.[pos ] <- char_of_digit k; ;; TEST_UNIT = for i = 0 to 999 do let s = String.make 3 ' ' in blit_string_of_int_3_digits s ~pos:0 i; <:test_result< string >> ~expect:(Printf.sprintf "%03d" i) s done ;; let parse_two_digits str pos = let d1 = Char.get_digit_exn str.[pos] in let d2 = Char.get_digit_exn str.[pos + 1] in 10 * d1 + d2 let parse_four_digits str pos = parse_two_digits str pos * 100 + parse_two_digits str (pos + 2) end (* Create an abstract type for Time to prevent us from confusing it with other floats. *) module T : sig type t = private float with bin_io include Comparable.S_common with type t := t include Hashable_binable with type t := t include Robustly_comparable with type t := t include Stringable with type t := t include Floatable with type t := t val add : t -> Span.t -> t val sub : t -> Span.t -> t val diff : t -> t -> Span.t val abs_diff : t -> t -> Span.t val now : unit -> t end = struct (* IF THIS REPRESENTATION EVER CHANGES, ENSURE THAT EITHER (1) all values serialize the same way in both representations, or (2) you add a new Time version to stable.ml *) include Float (* due to precision limitations in float we can't expect better than microsecond precision *) include Core_kernel.Float_robust_compare.Make (struct let robust_comparison_tolerance = 1E-6 end) let diff t1 t2 = Span.of_sec (t1 - t2) let abs_diff t1 t2 = Span.abs (diff t1 t2) let add t span = t +. (Span.to_sec span) let sub t span = t -. (Span.to_sec span) let now () = Unix.gettimeofday () end let float_of_hh_mm_ss hh mm ss = if hh < 0 then (Float.of_int (((hh * 60) - mm) * 60)) -. ss else (Float.of_int (((hh * 60) + mm) * 60)) +. ss let to_tm t = Unix.localtime (T.to_float t) let to_tm_utc t = Unix.gmtime (T.to_float t) (* this is a recreation of the algorithm used internally by the linux kernel (supposedly invented by Gauss). In this case it is used to produce the number of seconds since 1970-01-01 00:00:00 using epoch time semantics (86,400 seconds per day) *) let utc_mktime ~year ~month ~day ~ofday_sec = (* move February to the conceptual end of the ordering - 1..12 -> 11,12,1..10 - because it carries the leap day. The months are 0 indexed for this calculation, so 1 is February. *) let shuffle_year_month year month = let month = month - 2 in if month <= 0 then (year - 1, month + 12) else (year,month) in let year,month = shuffle_year_month year month in let days = year / 4 - year / 100 + year / 400 + 367 * month / 12 + day in let days = Float.of_int days +. 365. *. Float.of_int year -. 719499. in (days *. 86400. +. ofday_sec) ;; core-113.00.00/src/time_ns.ml000066400000000000000000000605431256461075500155460ustar00rootroot00000000000000INCLUDE "core_config.mlh" open Core_kernel.Std module Core_time = Time module KSpan = Core_kernel.Time_ns.Span module KTime_ns = Core_kernel.Time_ns (* This signature constraint is semi-temporary and serves to make the implementation more type-safe (so the compiler can help us more). It would go away if we broke the implementation into multiple files. *) module Span : sig include module type of (struct include KSpan end) include Identifiable with type t := t val to_short_string : t -> string val randomize : t -> percent : float -> t val to_span : t -> Time.Span.t val of_span : Time.Span.t -> t module Option : sig type span type t = private Int63.t with typerep include Identifiable with type t := t val none : t val some : span -> t val is_none : t -> bool val is_some : t -> bool val value : t -> default : span -> span val value_exn : t -> span module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io end end end with type span := t module Stable : sig module V1 : sig type nonrec t = t with bin_io, compare, sexp end end val random : unit -> t end = struct let half_microsecond = Int63.of_int 500 let nearest_microsecond t = Int63.((KSpan.to_int63_ns t + half_microsecond) /% of_int 1000) ;; let to_span t = Time.Span.of_us (Int63.to_float (nearest_microsecond t)) TEST "to_span +/-140y raises" = List.for_all [ 1.; -1. ] ~f:(fun sign -> does_raise (fun () -> to_span (KSpan.of_day (140. *. 366. *. sign)))) ;; let min_kspan_value = to_span KSpan.min_value let max_kspan_value = to_span KSpan.max_value let of_span s = if Time.Span.( > ) s max_kspan_value || Time.Span.( < ) s min_kspan_value then failwiths "Time_ns.Span does not support this span" s <:sexp_of< Time.Span.t >>; (* Using [Time.Span.to_sec] (being the identity) so that we make don't apply too many conversion - Too many : `[Span.t] -> [a] -> [KSpan.t]` - Only One : `[Span.t]==[a] -> [KSpan.t]`. *) KSpan.of_sec_with_microsecond_precision (Time.Span.to_sec s) ;; TEST "of_span +/-140y raises" = List.for_all [ 1.; -1. ] ~f:(fun sign -> does_raise (fun () -> of_span (Time.Span.of_day (140. *. 366. *. sign)))) ;; let random () = KSpan.of_int63_ns (let open Int63 in random KSpan.(to_int63_ns max_value) + random (of_int 2) - random KSpan.(to_int63_ns max_value) - random KSpan.(to_int63_ns (neg (max_value + min_value))) - random (of_int 2)) ;; TEST_UNIT "Time.Span.t -> Time_ns.Span.t round trip with microsecond precision" = let open Time.Span in let sexp_of_t t = sexp_of_float (to_float t) in (* more precise *) let time_spans = (* touchstones *) min_kspan_value :: max_kspan_value :: Time.(diff (now ()) epoch) :: Time.Span.([ zero; microsecond; millisecond; second; minute; hour; day; scale day 365. ]) in let time_spans = (* a few randoms *) time_spans @ List.init 9 ~f:(fun _ -> Time.Span.(of_us (Random.float (to_us max_kspan_value)))) in let time_spans = (* a few multiples *) List.concat_map time_spans ~f:(fun time_span -> List.map (List.range (-3) 4) ~f:(fun s -> Time.Span.scale time_span (float s))) in let time_spans = (* a few microseconds around *) List.concat_map time_spans ~f:(fun time_span -> List.map (List.range (-3) 4) ~f:(fun s -> Time.Span.(time_span + scale microsecond (float s)))) in let time_spans = (* nearest microsecond *) List.map time_spans ~f:(fun s -> Time.Span.(of_us (Float.round_nearest (to_us s)))) in let time_spans = (* in range *) List.filter time_spans ~f:(fun s -> Time.Span.(s >= min_kspan_value && s <= max_kspan_value)) in List.iter time_spans ~f:(fun expect -> <:test_result< t >> ~expect (to_span (of_span expect))) ;; TEST_UNIT "Time_ns.Span.t -> Time.Span.t round trip" = let open KSpan in (* The default sexp is not precise enough. *) let sexp_of_t kspan = Sexp.Atom (Int63.to_string (to_int63_ns kspan) ^ "ns") in let kspans = (* touchstones *) min_value :: max_value :: KTime_ns.(diff (now ()) epoch) :: [ zero; microsecond; millisecond; second; minute; hour; day; scale day 365. ] in let kspans = (* a few randoms *) kspans @ List.init 9 ~f:(fun _ -> of_us (Random.float (to_us max_value))) in (* Some tweaks will be out of range, which will raise exceptions. *) let filter_map list ~f = List.filter_map list ~f:(fun x -> Option.try_with (fun () -> f x)) in let kspans = (* a few multiples *) List.concat_map kspans ~f:(fun kspan -> filter_map (List.range (-3) 4) ~f:(fun s -> scale kspan (float s))) in let kspans = (* a few microseconds around *) List.concat_map kspans ~f:(fun kspan -> filter_map (List.range (-3) 4) ~f:(fun s -> kspan + scale microsecond (float s))) in let kspans = (* nearest microsecond *) List.map kspans ~f:(fun s -> of_int63_ns Int63.(nearest_microsecond s * of_int 1000)) in let kspans = (* in range *) List.filter kspans ~f:(fun s -> s >= min_value && s <= max_value) in List.iter kspans ~f:(fun expect -> let kspan = of_span (to_span expect) in <:test_pred< t * t >> (fun (a, b) -> abs (a - b) <= microsecond) (expect, kspan)) ;; module T = struct include KSpan let sexp_of_t t = Time.Span.Stable.V1.sexp_of_t (to_span t) let t_of_sexp s = of_span (Time.Span.Stable.V1.t_of_sexp s) let module_name = "Core.Std.Time_ns.Span" let to_string t = Time.Span.to_string (to_span t) let of_string s = of_span (Time.Span.of_string s) let hash t = Int63.hash (KSpan.to_int63_ns t) let compare = compare end include T include Comparable.Validate_with_zero (T) include Identifiable.Make (T) TEST = Time.Span.is_positive (to_span max_value) (* make sure no overflow *) let to_short_string t = Time.Span.to_short_string (to_span t) let randomize t ~percent = of_span (Time.Span.randomize (to_span t) ~percent) module Option = struct type span = t with sexp type t = Int63.t with bin_io, typerep, compare (* nanoseconds or none *) let none = Int63.min_value TEST "none is not a valid span" = does_raise (fun () -> of_int63_ns none) let some t = to_int63_ns t let is_none t = Int63.(t = none) let is_some t = Int63.(t <> none) let value t ~default = if is_none t then default else of_int63_ns t let value_exn t = assert (is_some t); of_int63_ns t let of_option = function None -> none | Some t -> some t let to_option t = if is_none t then None else Some (of_int63_ns t) let sexp_of_t t = <:sexp_of< span option >> (to_option t) let t_of_sexp s = of_option (<:of_sexp< span option >> s) include Identifiable.Make (struct type nonrec t = t with sexp, compare, bin_io let hash = Int63.hash let module_name = "Core.Std.Time_ns.Span.Option" include Sexpable.To_stringable (struct type nonrec t = t with sexp end) end) module Stable = struct module V1 = struct type nonrec t = t with sexp, bin_io end TEST_MODULE "Time_ns.Span.Stable.V1" = Core_kernel.Stable_unit_test.Make (struct include V1 let equal = Int63.equal let tests = let mk_some i = some (of_int63_ns (Int63.of_int64_exn i)) in [ none, "()", "\252\000\000\000\000\000\000\000\192" ; mk_some 1_234_560_000_000L, "(20.576m)", "\252\000\160\130q\031\001\000\000" ; mk_some 1_000L, "(0.001ms)", "\254\232\003" ; mk_some 80_000_006_400_000_000L, "(925.926d)", "\252\000@\128\251\1487\028\001" ] end) end end module Stable = struct module V1 = struct type nonrec t = t with bin_io, compare, sexp end TEST_MODULE "Time_ns.Span.Stable.V1" = Core_kernel.Stable_unit_test.Make (struct include V1 let equal = KSpan.equal let tests = let t i = of_int63_ns (Int63.of_int64_exn i) in [ t 1_234_560_000_000L, "20.576m", "\252\000\160\130q\031\001\000\000" ; t 1_000L, "0.001ms", "\254\232\003" ; t 80_000_006_400_000_000L, "925.926d", "\252\000@\128\251\1487\028\001" ] end) end end include (KTime_ns : module type of struct include KTime_ns end with module Span := Span) let nanosleep t = Span.of_sec (Core_unix.nanosleep (Span.to_sec t)) let pause_for t = let time_remaining = (* If too large a float is passed in (Span.max_value for instance) then nanosleep will return immediately, leading to an infinite and expensive select loop. This is handled by pausing for no longer than 100 days. *) nanosleep (Span.min t (Span.scale Span.day 100.)) in if Span.( > ) time_remaining Span.zero then `Remaining time_remaining else `Ok ;; (** Pause and don't allow events to interrupt. *) let rec pause span = match pause_for span with | `Remaining span -> pause span | `Ok -> () ;; (** Pause but allow events to interrupt. *) let interruptible_pause = pause_for let rec pause_forever () = pause Span.day; pause_forever () ;; let to_time t = Time.add Time.epoch (Span.to_span (to_span_since_epoch t)) ;; let min_time_value = to_time min_value let max_time_value = to_time max_value let of_time t = if Time.( < ) t min_time_value || Time.( > ) t max_time_value then failwiths "Time_ns does not support this time" t <:sexp_of< Time.t >>; of_span_since_epoch (Span.of_span (Time.diff t Time.epoch)) ;; let random () = KTime_ns.of_int63_ns_since_epoch (let max_ns = to_int63_ns_since_epoch max_value in let open Int63 in random max_ns + random (of_int 2) - random max_ns - (let extra = neg (max_ns + to_int63_ns_since_epoch KTime_ns.min_value) in (* Now that Core_kernel.Std.Time_ns.Span.min/max_value are symmetric around zero, watch out for that case. *) if extra = zero then zero else random extra) - random (of_int 2)) ;; TEST_UNIT "Time.t -> Time_ns.t round trip" = let open Time in let sexp_of_t t = <:sexp_of< t * float >> (t, to_float t) in (* more precise *) let us_since_epoch time = Time.(Span.to_us (diff time epoch)) in let min_us_since_epoch = us_since_epoch min_time_value in let max_us_since_epoch = us_since_epoch max_time_value in let time_of_us_since_epoch us_since_epoch = Time.(add epoch (Span.of_us (Float.round_nearest us_since_epoch))) in let times = (* touchstones *) [ min_time_value; Time.epoch; Time.now (); max_time_value ] in let times = (* a few units around *) List.concat_map times ~f:(fun time -> List.concat_map Time.Span.([ microsecond; millisecond; second; minute; hour; day; scale day 365. ]) ~f:(fun unit -> List.map (List.map ~f:float (List.range (-3) 4)) ~f:(fun s -> Time.add time (Time.Span.scale unit s)))) in let times = (* a few randoms *) times @ List.init 9 ~f:(fun _ -> Time.add Time.epoch (Time.Span.of_us (min_us_since_epoch +. Random.float (max_us_since_epoch -. min_us_since_epoch)))) in let times = (* nearest microsecond *) List.map times ~f:(fun time -> time_of_us_since_epoch (Float.round_nearest Time.(Span.to_us (diff time epoch)))) in let times = (* in range *) List.filter times ~f:(fun time -> Time.(time >= min_time_value && time <= max_time_value)) in List.iter times ~f:(fun expect -> let time = to_time (of_time expect) in (* We don't have full microsecond precision at the far end of the range. *) if expect < Time.of_string "2107-01-01 00:00:00" then <:test_result< t >> ~expect time else <:test_pred< t * t >> (fun (a, b) -> Span.(abs (diff a b) <= microsecond)) (expect, time)) ;; TEST_UNIT "Time_ns.t -> Time.t round trip" = let open Alternate_sexp in let ts = (* touchstones *) [ min_value; epoch; now (); max_value ] in (* Some tweaks will be out of range, which will raise exceptions. *) let filter_map list ~f = List.filter_map list ~f:(fun x -> Option.try_with (fun () -> f x)) in let ts = (* a few units around *) List.concat_map ts ~f:(fun time -> List.concat_map Span.([ microsecond; millisecond; second; minute; hour; day; scale day 365. ]) ~f:(fun unit -> filter_map (List.map ~f:float (List.range (-3) 4)) ~f:(fun s -> add time (Span.scale unit s)))) in let ts = (* a few randoms *) ts @ List.init 9 ~f:(fun _ -> random ()) in let ts = (* nearest microsecond since epoch *) List.map ts ~f:(fun time -> KTime_ns.of_int63_ns_since_epoch (let open Int63 in (KTime_ns.to_int63_ns_since_epoch time + of_int 500) /% of_int 1000 * of_int 1000)) in let ts = (* in range *) List.filter ts ~f:(fun t -> t >= min_value && t <= max_value) in List.iter ts ~f:(fun expect -> <:test_result< t >> ~expect (of_time (to_time expect))) ;; let sexp_of_t (t : t) : Sexp.t = Time.sexp_of_t (to_time t) let sexp_of_t_abs ~zone t = Sexp.List (List.map (String.split ~on:' ' (Time.to_string_abs ~zone (to_time t))) ~f:(fun s -> Sexp.Atom s) ) let t_of_sexp s : t = of_time (Time.t_of_sexp s) let to_string t = Time.to_string (to_time t) let of_string s = of_time (Time.of_string s) module Stable0 = struct module V1 = struct type nonrec t = t with bin_io, compare, sexp end TEST_MODULE "Time_ns.Stable.V1" = Core_kernel.Stable_unit_test.Make (struct include V1 let sexp_of_t = sexp_of_t_abs ~zone:Zone.utc let equal = equal let tests = let t i = of_span_since_epoch (Span.of_int63_ns (Int63.of_int64_exn i)) in [ t 1_234_560_000_000L, "(1970-01-01 00:20:34.560000Z)", "\252\000\160\130q\031\001\000\000" ; t 1_000L, "(1970-01-01 00:00:00.000001Z)", "\254\232\003" ; t 80_000_006_400_000_000L, "(1972-07-14 22:13:26.400000Z)", "\252\000@\128\251\1487\028\001" ] end) end module Option = struct type time = t with sexp, compare type t = Span.Option.t with bin_io, compare, typerep let none = Span.Option.none let some time = Span.Option.some (to_span_since_epoch time) let is_none = Span.Option.is_none let is_some = Span.Option.is_some let value t ~default = of_span_since_epoch (Span.Option.value ~default:(to_span_since_epoch default) t) let value_exn t = of_span_since_epoch (Span.Option.value_exn t) TEST_MODULE "round trip" = struct let roundtrip t = (value_exn (some t)) TEST_UNIT "epoch" = <:test_result< time >> (roundtrip epoch) ~expect:epoch TEST_UNIT "now" = let t = now () in <:test_result< time >> (roundtrip t) ~expect:t end TEST = is_error (Result.try_with (fun () -> value_exn none)) let of_option = function None -> none | Some t -> some t let to_option t = if is_none t then None else Some (value_exn t) let sexp_of_t t = <:sexp_of< time option >> (to_option t) let sexp_of_t_abs ~zone t = <:sexp_of< Sexp.t option >> (Option.map (to_option t) ~f:(sexp_of_t_abs ~zone) ) let t_of_sexp s = of_option (<:of_sexp< time option >> s) include Identifiable.Make (struct type nonrec t = t with sexp, compare, bin_io let module_name = "Core.Std.Time_ns.Option" let hash = Span.Option.hash include Sexpable.To_stringable (struct type nonrec t = t with sexp end) end) module Stable = struct module V1 = struct type nonrec t = t with sexp, bin_io end TEST_MODULE "Time_ns.Option.Stable.V1" = Core_kernel.Stable_unit_test.Make (struct include V1 let sexp_of_t = sexp_of_t_abs ~zone:Zone.utc let equal = Span.Option.equal let tests = let t i = of_span_since_epoch (Span.of_int63_ns (Int63.of_int64_exn i)) in [ none, "()", "\252\000\000\000\000\000\000\000\192" ; some (t 1_234_560_000_000L), "((1970-01-01 00:20:34.560000Z))", "\252\000\160\130q\031\001\000\000" ; some (t 1_000L), "((1970-01-01 00:00:00.000001Z))", "\254\232\003" ; some (t 80_000_006_400_000_000L), "((1972-07-14 22:13:26.400000Z))", "\252\000@\128\251\1487\028\001" ] end) end end let to_string_fix_proto zone t = Time.to_string_fix_proto zone (to_time t) let of_string_fix_proto zone s = of_time (Time.of_string_fix_proto zone s) include Identifiable.Make (struct type nonrec t = t with sexp, bin_io, compare let module_name = "Core.Std.Time_ns" let hash t = Int63.hash (to_int63_ns_since_epoch t) let of_string, to_string = of_string, to_string end) TEST_MODULE = struct TEST = epoch = of_span_since_epoch Span.zero TEST_UNIT "round trip from [Time.t] to [t] and back" = let times = List.map ~f:Time.of_float [ 0.0; 1.0; 1.123456789 ] in List.iter times ~f:(fun time -> let res = to_time (of_time time) in <:test_result< Time.t >> ~equal:Time.(=.) ~expect:time res ) TEST_UNIT "round trip from [t] to [Time.t] and back" = List.iter Span.([ zero; second; scale day 365. ]) ~f:(fun since_epoch -> let t = of_span_since_epoch since_epoch in let res = of_time (to_time t) in (* Allow up to 100ns discrepancy in a year due to float precision issues. *) let discrepancy = diff res t in if Span.(abs discrepancy > of_ns 100.) then failwiths "Failed on span since epoch" (`since_epoch since_epoch, t, `res res, `discrepancy discrepancy) <:sexp_of< [ `since_epoch of Span.t ] * t * [ `res of t ] * [ `discrepancy of Span.t ] >>) end (** Presently this is not zoned. *) module Ofday = struct type t = Span.t (* since midnight *) with typerep, compare, bin_io let start_of_day : t = Span.zero let end_of_day : t = Span.day let end_of_day_with_dst_and_leap_second_allowance : t = Span.(end_of_day + hour + minute) let to_span_since_start_of_day t = t let of_span_since_start_of_day_exn (s : Span.t) = if Span.(<) s start_of_day || Span.(>) s end_of_day_with_dst_and_leap_second_allowance then failwith "Time_ns.Ofday.of_span_since_start_of_day_exn: input out of bounds" else s let local_midnight time = let zone = Time.Zone.local in let date = Time.to_date (to_time time) ~zone in let midnight = Time.of_date_ofday date Time.Ofday.start_of_day ~zone in of_time midnight ;; let local_midnight_cache = ref (local_midnight (now ())) let of_local_time time = let t = diff time !local_midnight_cache in if Span.(>=) t start_of_day && Span.(<) t end_of_day then t else begin local_midnight_cache := local_midnight time; diff time !local_midnight_cache end ;; let local_now () = of_local_time (now ()) let to_string t = if Span.(<=) start_of_day t && Span.(<) t end_of_day then let ns = Span.to_int63_ns t in let s = Span.to_int_sec t in let m = s / 60 in let h = m / 60 in sprintf "%02d:%02d:%02d.%09d" h (m mod 60) (s mod 60) Int63.(to_int_exn (rem ns Span.(to_int63_ns second))) else "Incorrect day" ;; let to_millisecond_string t = if Span.(<=) start_of_day t && Span.(<) t end_of_day then let ms = Int63.(Span.to_int63_ns t / of_int 1_000_000) in let s = Int63.(ms / of_int 1000) in let m = Int63.(s / of_int 60) in let h = Int63.(m / of_int 60) in sprintf "%02d:%02d:%02d.%03d" Int63.(to_int_exn h) Int63.(to_int_exn (rem m (of_int 60))) Int63.(to_int_exn (rem s (of_int 60))) Int63.(to_int_exn (rem ms (of_int 1000))) else "Incorrect day" ;; let of_ofday core = Span.of_span (Time.Ofday.to_span_since_start_of_day core) let to_ofday t = Time.Ofday.of_span_since_start_of_day (Span.to_span t) let of_string s = of_ofday (Time.Ofday.of_string s) let t_of_sexp s : t = of_ofday (Time.Ofday.t_of_sexp s) let sexp_of_t (t : t) = Time.Ofday.sexp_of_t (to_ofday t) include Identifiable.Make (struct type nonrec t = t with sexp, compare, bin_io let module_name = "Core.Std.Time_ns.Ofday" let hash = Span.hash let of_string, to_string = of_string, to_string end) module Stable = struct module V1 = struct type nonrec t = t with sexp, bin_io end TEST_MODULE "Time_ns.Ofday.Stable.V1" = Core_kernel.Stable_unit_test.Make (struct include V1 let equal = Span.equal let tests = let t i = Span.of_int63_ns (Int63.of_int64_exn i) in [ t 0L, "00:00:00.000000", "\000" ; t 1_000L, "00:00:00.000001", "\254\232\003" ; t 1_234_560_000_000L, "00:20:34.560000", "\252\000\160\130q\031\001\000\000" ] end) end end TEST_MODULE = struct TEST_UNIT = let span = Span.create ~hr:8 ~min:27 ~sec:14 ~ms:359 () in let ofday = Ofday.of_span_since_start_of_day_exn span in let expected = "08:27:14.359" in let ms_str = Ofday.to_millisecond_string ofday in if String.(<>) ms_str expected then failwithf "Failed on Ofday.to_millisecond_string Got (%s) expected (%s)" ms_str expected () TEST_UNIT = (* Ensure that local_midnight_cache doesn't interfere with converting times that are much earlier or later than each other. *) let check ofday = let to_string t = Span.to_int63_ns t |> Int63.to_string in if Ofday.(<) ofday Ofday.start_of_day then failwithf "too small: %s" (to_string ofday) () else if Ofday.(>=) ofday Ofday.end_of_day then failwithf "too large: %s" (to_string ofday) () else () in check (Ofday.of_local_time epoch); check (Ofday.of_local_time (now ())); check (Ofday.of_local_time epoch) end let of_date_ofday ~zone date ofday = of_time (Core_time.of_date_ofday ~zone date (Ofday.to_ofday ofday)) ;; let to_date t ~zone = Core_time.to_date (to_time t) ~zone let occurrence what t ~ofday ~zone = of_time (Core_time.occurrence what (to_time t) ~ofday:(Ofday.to_ofday ofday) ~zone) ;; module Stable = struct include Stable0 module Span = Span .Stable module Option = Option .Stable module Ofday = Ofday .Stable end (* Dropping Time in favor of Time_ns is possible and has been discussed, but we have chosen not to do so at this time for a few reasons: - It's a lot of work. All functions over Time, including the related modules Date, Ofday, Zone, Span, Schedule have to be converted to Time_ns space. This is largely mechanical, but will create a lot of churn within the modules and possibly externally where the floatiness of the Time world leaks out. - It's of limited utility compared to other things we could be working on. Time math would be easier to understand and somewhat faster, but very few modules/programs would benefit from faster time math. Those that do can use Time_ns already for the most part. - Having Time_ns and a conversion function already gives the bulk of the value to programs that want a fast, non-allocating version of [Time.now]. Indeed, many remaining unconverted functions - We aren't certain about how the boundaries around Time_ns will affect the external viability of Core. Internally we don't think being limited to a smaller time range is an issue, and really far off times are better represented as (Date.t * Ofday.t), but it is still a restriction. This pushback is probably minimal and, if we could get over the work concerns, could be eliminated. - Converting between Time and Time_ns when you use libraries based on different ones isn't so bad. (?) *) core-113.00.00/src/time_ns.mli000066400000000000000000000175771256461075500157300ustar00rootroot00000000000000(** An absolute point in time, more efficient and precise than the [float]-based {!Time}, but representing a narrower range of times. This module represents absolute times with nanosecond precision, approximately between the years 1823 and 2116 CE. NOTE: you should normally default to using [Time] instead of this module. The reasons are: - Many functions around our libraries expect [Time.t] values, so it will likely be much more convenient for you. - It leads to greater consistency across different codebases. It would be bad to end up with half our libraries expecting [Time.t] and the other half expecting [Time_ns.t]. Some reasons you might want want to actually prefer [Time_ns.t] in certain cases: - It has superior performance. - It uses [int]s rather than [float]s internally, which makes certain things easier to reason about, since ints respect a bunch of arithmetic identities that floats don't, e.g., [x + (y + z) = (x + y) + z]. - It is available on non-UNIX platforms, including Javascript via js_of_ocaml. All in all, it would have been nice to have chosen [Time_ns.t] to begin with, but we're unlikely to flip everything to [Time_ns.t] in the short term (see comment at the end of time_ns.ml). *) open Core_kernel.Std type t = Core_kernel.Time_ns.t with typerep module Span : sig type t = Core_kernel.Time_ns.Span.t with typerep include Identifiable with type t := t (** Similar to {!Time.Span.Parts}, but adding [ns]. *) module Parts : sig type t = { sign : Float.Sign.t ; hr : int ; min : int ; sec : int ; ms : int ; us : int ; ns : int } with sexp end val nanosecond : t val microsecond : t val millisecond : t val second : t val minute : t val hour : t val day : t val of_ns : float -> t val of_us : float -> t val of_ms : float -> t val of_sec : float -> t val of_min : float -> t val of_hr : float -> t val of_day : float -> t val to_ns : t -> float val to_us : t -> float val to_ms : t -> float val to_sec : t -> float val to_min : t -> float val to_hr : t -> float val to_day : t -> float val of_int_sec : int -> t val to_int_sec : t -> int val zero : t val min_value : t val max_value : t val ( + ) : t -> t -> t val ( - ) : t -> t -> t val abs : t -> t val neg : t -> t val scale : t -> float -> t val scale_int : t -> int -> t val div : t -> t -> Int63.t val ( / ) : t -> float -> t val ( // ) : t -> t -> float val create : ?sign : Float.Sign.t -> ?day : int -> ?hr : int -> ?min : int -> ?sec : int -> ?ms : int -> ?us : int -> ?ns : int -> unit -> t val to_short_string : t -> string val randomize : t -> percent : float -> t val to_parts : t -> Parts.t val of_parts : Parts.t -> t (** {!Time.t} is precise to approximately 0.24us in 2014. If [to_span] converts to the closest [Time.Span.t], we have stability problems: converting back yields a different [t], sometimes different enough to have a different external representation, because the conversion back and forth crosses a rounding boundary. To stabilize conversion, we treat [Time.t] as having 1us precision: [to_span] and [of_span] both round to the nearest 1us. Around 135y magnitudes, [Time.Span.t] no longer has 1us resolution. At that point, [to_span] and [of_span] raise. The concern with stability is in part due to an earlier incarnation of [Timing_wheel] that had surprising behavior due to rounding of floating-point times. Timing_wheel was since re-implemented to use integer [Time_ns], and to treat floating-point [Time]s as equivalence classes according to the [Time_ns] that they round to. See [Timing_wheel_float] for details. *) val to_span : t -> Time.Span.t val of_span : Time.Span.t -> t include Robustly_comparable with type t := t val to_int63_ns : t -> Int63.t (** Fast, implemented as the identity function. *) val of_int63_ns : Int63.t -> t (** Fast, implemented as the identity function. *) (** Will raise on 32-bit platforms with spans corresponding to contemporary {!now}. Consider [to_int63_ns] instead. *) val to_int_ns : t -> int val of_int_ns : int -> t module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io end end val random : unit -> t module Option : sig type span type t = private Int63.t with typerep include Identifiable with type t := t val none : t val some : span -> t val is_none : t -> bool val is_some : t -> bool val value : t -> default : span -> span val value_exn : t -> span module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io end end end with type span := t end module Option : sig type time type t = private Int63.t with typerep include Identifiable with type t := t val none : t val some : time -> t val is_none : t -> bool val is_some : t -> bool val value : t -> default : time -> time val value_exn : t -> time val of_option : time option -> t val to_option : t -> time option module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io end end end with type time := t module Ofday : sig type time type t = private Int63.t with typerep include Identifiable with type t := t val to_ofday : t -> Time.Ofday.t val of_ofday : Time.Ofday.t -> t val local_now : unit -> t val of_local_time : time -> t val to_millisecond_string : t -> string val start_of_day : t val end_of_day : t val to_span_since_start_of_day : t -> Span.t (** [of_span_since_start_of_day_exn] excludes obviously impossible times of day but cannot exclude all invalid times of day due to DST, leap seconds, etc. *) val of_span_since_start_of_day_exn : Span.t -> t module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io end end end with type time := t include Identifiable with type t := t val epoch : t (** Unix epoch (1970-01-01 00:00:00 UTC) *) val min_value : t val max_value : t val now : unit -> t val add : t -> Span.t -> t val sub : t -> Span.t -> t val diff : t -> t -> Span.t val abs_diff : t -> t -> Span.t val to_span_since_epoch : t -> Span.t val of_span_since_epoch : Span.t -> t val to_time : t -> Time.t val of_time : Time.t -> t val to_string_fix_proto : [ `Utc | `Local ] -> t -> string val of_string_fix_proto : [ `Utc | `Local ] -> string -> t val to_int63_ns_since_epoch : t -> Int63.t val of_int63_ns_since_epoch : Int63.t -> t (** Will raise on 32-bit platforms. Consider [to_int63_ns_since_epoch] instead. *) val to_int_ns_since_epoch : t -> int val of_int_ns_since_epoch : int -> t (** See [Core_kernel.Time_ns] *) val next_multiple : ?can_equal_after:bool (** default is [false] *) -> base:t -> after:t -> interval:Span.t -> unit -> t val of_date_ofday : zone:Zone.t -> Date.t -> Ofday.t -> t val to_date : t -> zone:Zone.t -> Date.t val occurrence : [ `First_after_or_at | `Last_before_or_at ] -> t -> ofday:Ofday.t -> zone:Zone.t -> t (** [pause span] sleeps for [span] time. *) val pause : Span.t -> unit (** [interruptible_pause span] sleeps for [span] time unless interrupted (e.g. by delivery of a signal), in which case the remaining unslept portion of time is returned. *) val interruptible_pause : Span.t -> [ `Ok | `Remaining of Span.t ] (** [pause_forever] sleeps indefinitely. *) val pause_forever : unit -> never_returns module Stable : sig module V1 : sig type nonrec t = t with bin_io, compare, sexp end module Span : module type of Span .Stable module Option : module type of Option .Stable module Ofday : module type of Ofday .Stable end val random : unit -> t core-113.00.00/src/time_ns_benchmarks.ml000066400000000000000000000134641256461075500177430ustar00rootroot00000000000000(* Several benchmarks for [Time_ns]. These are not written inline in the [time_ns.ml] because they also try to test cost of assignment and hence rely on compiler optimization enabled by the [private int] declarations of [time_ns.mli]. ┌──────────────────────────────────────────────────────────────────────────────┬────────────┬─────────┬──────────┬──────────┬────────────┐ │ Name │ Time/Run │ mWd/Run │ mjWd/Run │ Prom/Run │ Percentage │ ├──────────────────────────────────────────────────────────────────────────────┼────────────┼─────────┼──────────┼──────────┼────────────┤ │ [time_ns_benchmarks.ml] Time_ns.now │ 28.93ns │ │ │ │ 1.96% │ │ [time_ns_benchmarks.ml] Time_ns.Ofday.local_now │ 33.49ns │ │ │ │ 2.27% │ │ [time_ns_benchmarks.ml] Time_ns.to_string │ 726.16ns │ 188.00w │ │ │ 49.30% │ │ [time_ns_benchmarks.ml] Time_ns.to_ofday │ 7.30ns │ │ │ │ 0.50% │ │ [time_ns_benchmarks.ml] Time_ns.to_int │ 1.90ns │ │ │ │ 0.13% │ │ [time_ns_benchmarks.ml] Time_ns.of_int │ 1.91ns │ │ │ │ 0.13% │ │ [time_ns_benchmarks.ml] Time_ns.Ofday.to_string │ 1_472.82ns │ 391.01w │ 0.10w │ 0.10w │ 100.00% │ │ [time_ns_benchmarks.ml] Time_ns.Span.of_hr │ 4.15ns │ 2.00w │ │ │ 0.28% │ │ [time_ns_benchmarks.ml] Time_ns.Span.of_min │ 4.51ns │ 2.00w │ │ │ 0.31% │ │ [time_ns_benchmarks.ml] Time_ns.Span.of_sec │ 4.15ns │ 2.00w │ │ │ 0.28% │ │ [time_ns_benchmarks.ml] Time_ns.Span.of_ms │ 4.97ns │ 2.00w │ │ │ 0.34% │ │ [time_ns_benchmarks.ml] Time_ns.Span.of_int_sec │ 2.70ns │ │ │ │ 0.18% │ │ [time_ns_benchmarks.ml] Time_ns.Span.to_int_sec │ 9.14ns │ │ │ │ 0.62% │ │ [time_ns_benchmarks.ml] Time_ns.t assignment │ 2.18ns │ │ │ │ 0.15% │ │ [time_ns_benchmarks.ml] Time.t assignment │ 7.23ns │ │ │ │ │ │ [time_ns_benchmarks.ml] Time_ns.of_time │ 11.86ns │ 4.00w │ │ │ │ │ [time_ns_benchmarks.ml] Time_ns.of_time (Async.Std.Scheduler.cycle_start ()) │ 16.45ns │ 4.00w │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┴────────────┴─────────┴──────────┴──────────┴────────────┘ *) module Time_ns_in_this_directory = Time_ns open Core_kernel.Std module Time_ns = Time_ns_in_this_directory BENCH "Time_ns.now" = Time_ns.now () BENCH "Time_ns.Ofday.local_now" = Time_ns.Ofday.local_now () BENCH_FUN "Time_ns.to_string" = let t = Time_ns.now () in (fun () -> Time_ns.to_string t) BENCH_FUN "Time_ns.to_ofday" = let t = Time_ns.now () in (fun () -> Time_ns.Ofday.of_local_time t) BENCH_FUN "Time_ns.to_int63_ns_since_epoch" = let t = Time_ns.now () in (fun () -> Time_ns.Span.to_int63_ns (Time_ns.to_span_since_epoch t)) BENCH_FUN "Time_ns.of_int63_ns_since_epoch" = let t = Int63.of_string "100000" in (fun () -> Time_ns.of_span_since_epoch (Time_ns.Span.of_int63_ns t)) BENCH_FUN "Time_ns.Ofday.to_string" = let t = Time_ns.Ofday.of_local_time (Time_ns.now ()) in (fun () -> Time_ns.Ofday.to_string t) BENCH "Time_ns.Span.of_day" = Time_ns.Span.of_day 0.1 BENCH "Time_ns.Span.of_hr" = Time_ns.Span.of_hr 0.1 BENCH "Time_ns.Span.of_min" = Time_ns.Span.of_min 0.1 BENCH "Time_ns.Span.of_sec" = Time_ns.Span.of_sec 0.1 BENCH "Time_ns.Span.of_ms" = Time_ns.Span.of_ms 0.1 BENCH "Time_ns.Span.of_int_sec" = Time_ns.Span.of_int_sec 10000 BENCH_FUN "Time_ns.Span.to_int_sec" = let t = Time_ns.to_span_since_epoch (Time_ns.now ()) in (fun () -> Time_ns.Span.to_int_sec t) BENCH_FUN "Time_ns.t assignment" = let t = Time_ns.now () in let x : Time_ns.t ref = ref t in (fun () -> x := t) BENCH_FUN "Time.t assignment" = let t = Time.now () in let x : Time.t ref = ref t in (fun () -> x := t) BENCH_FUN "Time_ns.of_time" = let time = Time.now () in (fun () -> Time_ns.of_time time) core-113.00.00/src/time_ns_stubs.c000066400000000000000000000017501256461075500165730ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include "ocaml_utils.h" #include "core_config.h" #define NANOS_PER_SECOND 1000000000 #if defined(JSC_POSIX_TIMERS) #define clockid_t_val(v_cl) ((clockid_t) Nativeint_val(v_cl)) CAMLprim value core_time_ns_gettime_or_zero() { struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) != 0) return caml_alloc_int63(0); else return caml_alloc_int63(NANOS_PER_SECOND * ts.tv_sec + ts.tv_nsec); } #else #include #include CAMLprim value core_time_ns_gettime_or_zero() { struct timeval tp; if (gettimeofday(&tp, NULL) == -1) return caml_alloc_int63(0); else return caml_alloc_int63(NANOS_PER_SECOND * tp.tv_sec + tp.tv_usec * 1000); } #endif core-113.00.00/src/time_stamp_counter.ml000066400000000000000000000453471256461075500200160ustar00rootroot00000000000000(* Time stamp counter ================== This module tries to estimate time based on the CPU time stamp counter (TSC). The time estimates reported by this module are monotonically increasing. It uses [Time.now ()] as its measure of "real time" to do this. Historically, the rate of increment of the TSC (sometimes referred to as the TSC frequency) varied based of CPU overclocking, temperature, load etc. On modern Intel CPU's the TSC is expected to be stable. On Linux systems, the "constant_tsc" in /proc/cpuinfo indicates that the machine has a stable TSC rate. While this module assumes that the TSC is relatively stable, it can adapt to small variations in the TSC frequency. Simple Overview =============== Here is an explanation of how this module works. The module measures the change in real time and the change in TSC at every calibration call and maintains an EWMA of these deltas. It then uses the EWMA values to do linear regression where time is the estimated value and TSC is the predictor. The linear regression done at every calibration step produces an updated time/tsc slope. Using this time/tsc slope and the latest value of real time, the module estimates time in terms of tsc. Ensuring Monotonicity of Time ============================= The simple picture above is complicated by the presence of noise. There are two significant sources of noise. The first is the noise caused by variations in the frequency of TSC. The second, and probably the more significant one, is noise in real time, i.e. noise in the [Time.now ()] call. (1) [Time.now ()] calls suffer from the overhead of transition from the the user program to a kernel vdso and (2) It is affected by NTP updates. (3) Another significant source of error comes from loss of precision. [Time.now] reports a 64-bit float of which it has 52 bits of mantissa. The 52 bits of mantissa for time in seconds from Unix epoch only allows for precision in the order of micro-seconds. Consequently the measurement of time using [Time.now] can only be precise in the order of micro-seconds. Noise in measuring real time and in the rate of time/tsc implies that at each calibration point the estimated time "jumps" up or down with respect to the estimate value of time before calibration. In other words, the time estimated using the EWMA linear regression is not strictly monotonic. We report a monotonic time in terms of the estimated time, by maintaining a separate slope called the "monotonic time/TSC slope". At every calibration point, we take the last estimated time and adjust the monotonic time/TSC slope such that it catches up to the estimated time in a fixed number of cycles. If the expected change in slope is too high, we bound the rate of change of the monotonic time/TSC slope. As long as monotonic time has not caught up with the estimated time we report time in terms of the adjusted monotonic time slope. Once we have caught up to the estimated time, we start reporting the estimated time. We can chose the number of cycles to allow for catchup to be any number we wish. A number in the order of 1E6-1E9 TSC steps allows for a gradual catchup rate without too many abrupt changes in the rate of reported time. The bound to rate of change is expressed in percentage terms of slope and is at max the ratio by which we expect the underlying TSC frequency to change on the machine. It is defined as [max_perc_change_from_real_slope] below. It is worth noting that the approximation of the monotonic slope trying to catch up with the estimate slope can be achieved in many other ways. A more principled approach to this would be to use a PID controller that adapts to error and gets the reported monotonic time to smoothly fit the estimated time. However PID controllers are computationally more expensive and we use a simpler linear approximation. *) INCLUDE "core_config.mlh" open Core_kernel.Std module Unix = Core_unix let max_percent_change_from_real_slope = 0.20 TEST_UNIT = assert (0. <= max_percent_change_from_real_slope); assert (max_percent_change_from_real_slope <= 1.); ;; let ewma ~alpha ~old ~add = ((1. -. alpha) *. old) +. (alpha *. add) type t = Int63.t with bin_io, compare, sexp type tsc = t with bin_io, compare, sexp let diff t1 t2 = Int63.(-) t1 t2 let add t s = Int63.(+) t s let to_int63 t = t IFDEF ARCH_SIXTYFOUR THEN (* noalloc on x86_64 only *) external now : unit -> tsc = "tsc_get" "noalloc" module Calibrator = struct type t = { (* the most recent observations and regression results *) mutable time : float ; mutable tsc : tsc ; mutable sec_per_cycle : float (* mutable sec_error_intercept : float; *) (* this time value is monotonically increasing *) ; mutable monotonic_time : float ; mutable monotonic_sec_per_cycle : float ; mutable monotonic_until_tsc : tsc (* for linear regression *) ; mutable ewma_time_tsc : float ; mutable ewma_tsc_square : float ; mutable ewma_time : float ; mutable ewma_tsc : float (* for computing time in nanos *) ; mutable time_nanos : Int63.t ; mutable nanos_per_cycle : float ; mutable monotonic_time_nanos : Int63.t ; mutable monotonic_nanos_per_cycle : float } with bin_io, sexp let tsc_to_time = let convert t tsc base mul = Time.of_float (base +. (mul *. Int63.to_float (diff tsc t.tsc))) in fun t tsc -> if tsc < t.monotonic_until_tsc then convert t tsc t.monotonic_time t.monotonic_sec_per_cycle else convert t tsc t.time t.sec_per_cycle ;; let tsc_to_nanos_since_epoch = let convert t tsc base mul = (* Scale an int by a float without intermediate allocation and overflow. *) Int63.(+) base (Float.int63_round_nearest_exn (mul *. Int63.to_float (diff tsc t.tsc))) in fun t tsc -> if tsc < t.monotonic_until_tsc then convert t tsc t.monotonic_time_nanos t.monotonic_nanos_per_cycle else convert t tsc t.time_nanos t.nanos_per_cycle ;; (* The rate of response to the variations in TSC frequency can be controlled via alpha. Alpha should be in (0,1] and controls the decay of the subsequent EWMA calculation. A low number such as 0.01 suggests that the TSC is largely stable and small variations should be treated as noise. Setting this number to 0.6 or higher indicates that each new measurement of the TSC should significantly outweigh past measurements which has the effect of making time calibration more responsive to frequency changes. In this module we have chosen a value of alpha that varies with the duration of time, i.e. longer time samples are given more weight and shorter time samples are given lesser weight. *) let alpha_for_interval time_diff = 1. -. exp (-0.5 *. time_diff) ;; let catchup_cycles = 1E9 let initial_alpha = 1. let calibrate_using t ~tsc ~time ~am_initializing = let estimated_time = Time.to_float (tsc_to_time t tsc) in let time_diff_est = time -. estimated_time in let time_diff = time -. t.time in let tsc_diff = Int63.to_float (diff tsc t.tsc) in let alpha = if am_initializing then initial_alpha else alpha_for_interval time_diff in (* update current times *) t.time <- time; t.tsc <- tsc; (* update ewma and regression. *) t.ewma_time_tsc <- ewma ~alpha ~old:t.ewma_time_tsc ~add:(tsc_diff *. time_diff); t.ewma_tsc_square <- ewma ~alpha ~old:t.ewma_tsc_square ~add:(tsc_diff *. tsc_diff); t.ewma_tsc <- ewma ~alpha ~old:t.ewma_tsc ~add:tsc_diff; t.ewma_time <- ewma ~alpha ~old:t.ewma_time ~add:time_diff; (* linear regression *) t.sec_per_cycle <- t.ewma_time_tsc /. t.ewma_tsc_square; (* t.sec_error_intercept <- t.ewma_time -. t.sec_per_cycle *. t.ewma_tsc; *) (* monotonic predicted time and slope. *) t.monotonic_time <- estimated_time; if not am_initializing then begin let catchup_sec_per_cycle = (* The slope so that after [catchup_cycles], the monotonic estimated time equals the estimated time, i.e. solve for [monotonic_sec_per_cycle] in: {[ t.monotonic_time + monotonic_sec_per_cyle * catchup_cycles = t.time + t.sec_per_cycle * catchup_cycles ]} Note that [time_diff_est = t.time - t.monotonic_time]. *) t.sec_per_cycle +. (time_diff_est /. catchup_cycles) in t.monotonic_sec_per_cycle <- if Float.is_positive time_diff_est then Float.min catchup_sec_per_cycle (t.sec_per_cycle *. (1. +. max_percent_change_from_real_slope)) else Float.max catchup_sec_per_cycle (t.sec_per_cycle *. (1. -. max_percent_change_from_real_slope)); (* Compute the number of cycles in the future at which monotonic estimated time equals estimated time, i.e. solve for [cycles] in: {[ t.monotonic_time + t.monotonic_sec_per_cyle * cycles = t.time + t.sec_per_cycle * cycles ]} This value might get very small when the two slopes are about the same. In such cases we just use the estimated slope always. *) t.monotonic_until_tsc <- (match Float.iround_up (time_diff_est /. (t.monotonic_sec_per_cycle -. t.sec_per_cycle)) with | Some x -> add tsc (Int63.of_int x) | None -> Int63.zero); end; (* Precompute values required for [tsc_to_nanos_since_epoch]. *) t.time_nanos <- Float.int63_round_nearest_exn (t.time *. 1E9); t.nanos_per_cycle <- t.sec_per_cycle *. 1E9; t.monotonic_time_nanos <- Float.int63_round_nearest_exn (t.monotonic_time *. 1E9); t.monotonic_nanos_per_cycle <- t.monotonic_sec_per_cycle *. 1E9; ;; let now_float () = Time.to_float (Time.now ()) let initialize t samples = List.iter samples ~f:(fun (tsc, time) -> calibrate_using t ~tsc ~time ~am_initializing:true); ;; let collect_samples ~num_samples ~interval = assert (num_samples >= 1); (* We sleep at differing intervals to improve the estimation of [sec_per_cycle]. *) let rec loop n sleep = let sample = (now (), now_float ()) in if n = 1 then [sample] else begin ignore (Unix.nanosleep sleep); sample :: loop (n-1) (sleep +. interval) end in loop num_samples interval ;; let create () = let now_float = now_float () in let t = { monotonic_time = now_float ; monotonic_sec_per_cycle = 0. ; monotonic_until_tsc = Int63.zero ; time = now_float ; tsc = now () ; sec_per_cycle = 0. ; ewma_time_tsc = 0. ; ewma_tsc_square = 0. ; ewma_time = 0. ; ewma_tsc = 0. ; time_nanos = Int63.zero ; nanos_per_cycle = 0. ; monotonic_time_nanos = Int63.zero ; monotonic_nanos_per_cycle = 0. } in initialize t (collect_samples ~num_samples:3 ~interval:0.0005); t ;; (* Creating a calibrator takes about 3ms and is fast enough that we don't mind paying for it at startup. *) let local = create () let cpu_mhz = Ok (fun ?(t = local) () -> 1. /. (t.sec_per_cycle *. 1E6)) let calibrate ?(t = local) () = calibrate_using t ~tsc:(now ()) ~time:(now_float ()) ~am_initializing:false ;; end ELSE (* noalloc on x86_64 only *) external now : unit -> tsc = "tsc_get" (** Outside of x86_64, [now] returns the result of clock_gettime(), i.e. the current time in nanos past epoch. *) module Calibrator = struct type t = unit with bin_io, sexp let tsc_to_time _t tsc = Time.of_float (Int63.to_float tsc *. 1e-9) let tsc_to_nanos_since_epoch _t tsc = tsc let create () = () let initialize _t _samples = () let calibrate_using _t ~tsc:_ ~time:_ ~am_initializing:_ = () let calibrate ?t:_ () = () let local = create () let cpu_mhz = Or_error.unimplemented "\ Time_stamp_counter.Calibrator.cpu_mhz is not defined for 32-bit platforms" ;; end ENDIF module Span = struct include Int63 IFDEF ARCH_SIXTYFOUR THEN let to_ns ?(calibrator = Calibrator.local) t = Float.int63_round_nearest_exn (Int63.to_float t *. calibrator.Calibrator.nanos_per_cycle) ;; let of_ns ?(calibrator = Calibrator.local) ns = Float.int63_round_nearest_exn (Int63.to_float ns /. calibrator.Calibrator.nanos_per_cycle) ;; ELSE (* [tsc_get] already returns the current time in ns *) let to_ns ?calibrator:_ t = t let of_ns ?calibrator:_ ns = ns ENDIF let to_time_span ?calibrator t = Span.of_ns (Int63.to_float (to_ns ?calibrator t)) ;; end let to_time ?(calibrator = Calibrator.local) t = Calibrator.tsc_to_time calibrator t let to_nanos_since_epoch ~calibrator t = Calibrator.tsc_to_nanos_since_epoch calibrator t; ;; let to_time_ns ?(calibrator = Calibrator.local) t = Time_ns.of_int63_ns_since_epoch (to_nanos_since_epoch ~calibrator t) ;; TEST_MODULE = struct (* monotonicity testing *) TEST_UNIT = let calibrator = Calibrator.create () in let last = ref 0. in for i = 1 to 10_000_000 do let cur = Time.to_float (to_time ~calibrator (now ())) in (* printf "%d %.9f\n%!" i (cur -. !last); *) if Float.(<) (cur -. !last) 0. then failwithf "Time is not monotonic (diff %.12f)" (cur -. !last) (); last := cur; if i mod 100_000 = 0 then Calibrator.calibrate ~t:calibrator (); done ;; module Samples = struct type t = (tsc * float) list with sexp let load file = Sexp.load_sexp_conv_exn file <:of_sexp< t >> end (* The following tests check to see that the errors in presampled data are within acceptable bounds. Errors are checked at two different sampling rates to simulate calls to [Calibrator.calibrate] at different rates to tests how errors accumulate in this module.*) let test_time_and_cycles samples_file ~error_limit ~alpha ~verbose = let samples = Samples.load samples_file in let init_samples, samples = List.split_n samples 3 in let calibrator = Calibrator.create () in let scale_us_abs t = Float.abs (t *. 1_000_000.) in Calibrator.initialize calibrator init_samples; let ewma_error = ref 0. in List.iter samples ~f:(fun (tsc, time) -> let cur_error = scale_us_abs (time -. Time.to_float (to_time ~calibrator tsc)) in ewma_error := ewma ~alpha ~old:!ewma_error ~add:cur_error; if verbose then printf "%f %f %s %f\n%!" cur_error !ewma_error (Int63.to_string tsc) time; if Float.(>=) (Float.abs !ewma_error) error_limit then failwithf "Average error %fus (current error %fus) of estimated time is \ beyond acceptable limits of %fus." !ewma_error cur_error error_limit (); Calibrator.calibrate_using calibrator ~tsc ~time ~am_initializing:false) ;; (* For this test, the data sample consists of 2,000 samples of Time.t and TSC.t sampled randomly with intervals up to 1sec. The error ewma of absolute error is atmost 1.2us, and the actual error ranges between 7.6us and -1.4us. It is worth noting that the errors are usually in the range of 1us and only occassionaly spike to the max/min values mentioned.*) TEST_UNIT = test_time_and_cycles ~error_limit:3. ~alpha:0.1 ~verbose:false "time_stamp_counter_samples_at_1sec.sexp" ;; (* For this test, the data sample consists of 600 samples of Time.t and TSC.t sampled randomly with intervals up to 1minute. Errors range between -8.5 and 7.6 us and ewma of absolute error goes upto about 2.4us. The errors in this case tend to oscillate between +/-5us. *) TEST_UNIT = test_time_and_cycles ~error_limit:3. ~alpha:0.1 ~verbose:false "time_stamp_counter_samples_at_60sec.sexp" ;; (* Test error magnitude in pre-sampled data. *) let test_time_and_cycles_nanos samples_file ~error_limit ~alpha ~verbose = let samples = Samples.load samples_file in let init_samples, samples = List.split_n samples 3 in let calibrator = Calibrator.create () in let scale_us_abs t = Float.abs (t *. 0.001) in Calibrator.initialize calibrator init_samples; let ewma_error = ref 0. in List.iter samples ~f:(fun (tsc, time) -> let time_nanos = Float.int63_round_nearest_exn (time *. 1E9) in let cur_error = scale_us_abs (Int63.to_float (diff time_nanos (to_nanos_since_epoch ~calibrator tsc))) in ewma_error := ewma ~alpha ~old:!ewma_error ~add:cur_error; if verbose then printf "%f %f\n%!" cur_error !ewma_error; if Float.(>=) (Float.abs !ewma_error) error_limit then failwithf "Average error %fus (current error %fus) of estimated time is \ beyond acceptable limits of %fus." !ewma_error cur_error error_limit (); Calibrator.calibrate_using calibrator ~tsc ~time ~am_initializing:false) ;; (* Error profiles for the nanos tests are similar to those of the float cases above. *) TEST_UNIT = test_time_and_cycles_nanos ~error_limit:500. ~alpha:0.1 ~verbose:false "time_stamp_counter_samples_at_1sec.sexp" ;; TEST_UNIT = test_time_and_cycles_nanos ~error_limit:3. ~alpha:0.1 ~verbose:false "time_stamp_counter_samples_at_60sec.sexp" ;; IFDEF ARCH_SIXTYFOUR THEN TEST_UNIT = let calibrator = Calibrator.local in for x = 1 to 100_000 do let y = x |> Int63.of_int |> Span.of_ns ~calibrator |> Span.to_ns ~calibrator |> Int63.to_int_exn in (* Accept a difference of at most [nanos_per_cycle] because of the precision lost during float truncation. [trunc (x / nanos_per_cycle) * nanos_per_cycle] *) assert (abs (x - y) <= Float.to_int calibrator.nanos_per_cycle); done ;; TEST_UNIT = let calibrator = Calibrator.local in for x = 1 to 100_000 do let y = x |> Int63.of_int |> Span.to_ns ~calibrator |> Span.of_ns ~calibrator |> Int63.to_int_exn in (* Accept a difference of at most [1/nanos_per_cycle] because of the precision lost during float truncation. [trunc (x * nanos_per_cycle) / nanos_per_cycle] *) assert (abs (x - y) <= Float.to_int (1. /. calibrator.nanos_per_cycle)); done ;; ENDIF end core-113.00.00/src/time_stamp_counter.mli000066400000000000000000000122431256461075500201540ustar00rootroot00000000000000(** High-performance timing. This module provides the fast function [now ()] which is our best effort high-performance cycle counter for a given platform. For x86 systems this retrieves the CPU's internal time stamp counter using the RDTSC instruction. For systems that do not have a RDTSC instruction, we fallback to using [clock_gettime(CLOCK_MONOTONIC)]. Here is a benchmark of execution time in nanos and allocations in words: {v Name Time/Run mWd/Run ---------------------------- ---------- --------- Time.now 37.93ns 2.00w Time_ns.now 28.18ns TSC.Calibrator.calibrate 115.43ns 28.00w TSC.now 7.14ns TSC.to_time 3.44ns 2.00w TSC.to_time (TSC.now ()) 8.24ns 2.00w TSC.to_time_ns 14.20ns TSC.to_time_ns(TSC.now ()) 9.80ns id 2.91ns TSC.Span.of_ns 5.81ns TSC.Span.to_ns 3.70ns v} Type [t] is an [Int63.t] and consequently has no allocation overhead (on 64-bit machines), unlike [Time.now ()] which returns a boxed float. Functions are also provided to estimate the relationship of CPU time-stamp-counter frequency to real time, thereby allowing one to convert from [t] to [Time.t]. There are some caveats to this that are worth noting: - The conversion to [Time.t] depends on an estimate of the time-stamp-counter frequency. This frequency may be volatile on some systems, thereby reducing the utility of this conversion. See the [Calibrator] module below for details. - The captured [t] can only be converted to a [Time.t] if one also has a recently calibrated [Calibrator.t] from the same machine. See also: http://en.wikipedia.org/wiki/Time_Stamp_Counter *) INCLUDE "core_config.mlh" open Core_kernel.Std type t = private Int63.t with bin_io, compare, sexp (** A calibrator contains a snapshot of machine-specific information that is used to convert between TSC values and clock time. This information needs to be calibrated periodically such that it stays updated w.r.t. changes in the CPU's time-stamp-counter frequency, which can vary depending on load, heat etc. (Also see the comment in the [.ml] file) Calibration at the rate of 0.1, 1 or 2 secs produces errors (measured as the difference between [Time.now] and the reported time here) on the order of 1-2us. Given the precision of 52bit float mantissa values, this is very close to least error one can have on these values. Calibration once per 10sec produces errors that are +/-4us. Calibration once per minute produces errors that are +/-15us and calibration once in 3mins produces errors +/-30us. (It is worth remarking that the error has a positive bias of 1us -- i.e. the error dances around the 1us mark, rather than around 0. It is unclear where this bias is introduced, though it probably does not matter for most applications.) This module maintains an instance of [t] internal to the module. The internal instance of [t] can be updated via calls to [calibrate ()], i.e. without specifying the [t] parameter. In all the functions below that take an optional [Calibrator.t] argument, the internal instance is used when no calibrator is explicitly specified. *) module Calibrator : sig type t with bin_io, sexp (** [create ()] creates an uninitialized calibrator instance. Creating a calibrator takes about 3ms. One needs a recently calibrated [Calibrator.t] and the TSC value from the same machine to meaningfully convert the TSC value to a [Time.t]. *) val create : unit -> t (** [calibrate ~t] updates [t] by measuring the current value of the TSC and [Time.now]. *) val calibrate : ?t:t -> unit -> unit (** Returns the estimated MHz of the CPU's time-stamp-counter based on the TSC and [Time.now ()]. This function is undefined on 32bit machines. *) val cpu_mhz : (?t:t -> unit -> float) Or_error.t end (** [Span] indicates some integer number of cycles. *) module Span : sig type t = private Int63.t with bin_io, sexp include Comparable with type t := t include Intable with type t := t val ( + ) : t -> t -> t val ( - ) : t -> t -> t val to_time_span : ?calibrator:Calibrator.t -> t -> Time.Span.t val to_ns : ?calibrator:Calibrator.t -> t -> Int63.t val of_ns : ?calibrator:Calibrator.t -> Int63.t -> t end IFDEF ARCH_SIXTYFOUR THEN external now : unit -> t = "tsc_get" "noalloc" ELSE external now : unit -> t = "tsc_get" ENDIF val diff : t -> t -> Span.t val add : t -> Span.t -> t (** [to_int63 t] returns the TSC value represented by [t] as an [Int63.t]. *) val to_int63 : t -> Int63.t (** [to_time t] converts a [t] to a [Time.t]. It is guaranteed that repeated calls of [to_time ()] will return nondecreasing [Time.t] values. *) val to_time : ?calibrator:Calibrator.t -> t -> Time.t (** [to_time_ns t] converts a [t] to an integer number of nanos since the epoch. *) val to_time_ns : ?calibrator:Calibrator.t -> t -> Time_ns.t core-113.00.00/src/time_stamp_counter_benchmarks.ml000066400000000000000000000013661256461075500222040ustar00rootroot00000000000000module TSC = Time_stamp_counter BENCH "Time.now" = Time.now () BENCH "Time_ns.now" = Time_ns.now () BENCH "TSC.Calibrator.calibrate" = TSC.Calibrator.calibrate () BENCH "TSC.now" = TSC.now () BENCH_FUN "TSC.to_time" = let c = TSC.now () in (fun () -> ignore (TSC.to_time c)) BENCH "TSC.to_time (TSC.now ())" = TSC.to_time (TSC.now ()) BENCH_FUN "TSC.to_time_ns" = let c = TSC.now () in (fun () -> ignore (TSC.to_time_ns c)) BENCH "TSC.to_time_ns(TSC.now ())" = TSC.to_time_ns (TSC.now ()) BENCH "id" = () BENCH_FUN "TSC.Span.of_ns" = let c = Core_kernel.Std.Int63.of_int_exn 123 in (fun () -> TSC.Span.of_ns c) BENCH_FUN "TSC.Span.to_ns" = let c = Core_kernel.Std.Int63.of_int_exn 123 |> TSC.Span.of_ns in (fun () -> TSC.Span.to_ns c) core-113.00.00/src/time_stamp_counter_samples_at_1sec.sexp000066400000000000000000002203121256461075500234730ustar00rootroot00000000000000( (5478415723468994 1378330632.996984) (5478418006666496 1378330633.670042) (5478418080126846 1378330633.691697) (5478419092374234 1378330633.990094) (5478421779093418 1378330634.782105) (5478422295905064 1378330634.934454) (5478424057634554 1378330635.453790) (5478427356907964 1378330636.426374) (5478429790949274 1378330637.143898) (5478432305487758 1378330637.885152) (5478434439431024 1378330638.514211) (5478436691835348 1378330639.178191) (5478438817880908 1378330639.804922) (5478440893994748 1378330640.416934) (5478442418288188 1378330640.866276) (5478443389368128 1378330641.152538) (5478443975362600 1378330641.325282) (5478445460957494 1378330641.763216) (5478448117102146 1378330642.546214) (5478449383405872 1378330642.919504) (5478450632635122 1378330643.287761) (5478451920340446 1378330643.667360) (5478454656496098 1378330644.473944) (5478455339792406 1378330644.675371) (5478457061686172 1378330645.182963) (5478459478762220 1378330645.895486) (5478461498257840 1378330646.490808) (5478461668836374 1378330646.541092) (5478464163895452 1378330647.276604) (5478464768570882 1378330647.454854) (5478466655294012 1378330648.011036) (5478468549266656 1378330648.569356) (5478469705391028 1378330648.910166) (5478470680353896 1378330649.197573) (5478471652439244 1378330649.484131) (5478471954776406 1378330649.573256) (5478472886794674 1378330649.848003) (5478476057249318 1378330650.782613) (5478479105283002 1378330651.681134) (5478480697370818 1378330652.150462) (5478481067347548 1378330652.259526) (5478483838311822 1378330653.076371) (5478486485922864 1378330653.856853) (5478489374620120 1378330654.708404) (5478490866491346 1378330655.148189) (5478493463800902 1378330655.913842) (5478493813598716 1378330656.016958) (5478495354647500 1378330656.471240) (5478498382571510 1378330657.363833) (5478500760202814 1378330658.064729) (5478501376229894 1378330658.246325) (5478501530417904 1378330658.291778) (5478504816281044 1378330659.260409) (5478507067490522 1378330659.924036) (5478508396162556 1378330660.315712) (5478511618630060 1378330661.265654) (5478513685491990 1378330661.874939) (5478515433424986 1378330662.390207) (5478518557335756 1378330663.311096) (5478521517670450 1378330664.183765) (5478522216925144 1378330664.389896) (5478524391873762 1378330665.031044) (5478525332081958 1378330665.308205) (5478528027234418 1378330666.102702) (5478530698597672 1378330666.890186) (5478532491203414 1378330667.418623) (5478533019107362 1378330667.574242) (5478536127551728 1378330668.490572) (5478539422595860 1378330669.461910) (5478541248124639 1378330670.000052) (5478544151308788 1378330670.855874) (5478546704088280 1378330671.608401) (5478548776504374 1378330672.219323) (5478551067846092 1378330672.894781) (5478552225085248 1378330673.235920) (5478553884995508 1378330673.725241) (5478556326431664 1378330674.444945) (5478557963074330 1378330674.927407) (5478560791026046 1378330675.761051) (5478564011464158 1378330676.710395) (5478564969125566 1378330676.992701) (5478566915037792 1378330677.566331) (5478567030511592 1378330677.600371) (5478570157953354 1378330678.522302) (5478571770084986 1378330678.997538) (5478573494835898 1378330679.505972) (5478574210666458 1378330679.716990) (5478577023973628 1378330680.546317) (5478578155710948 1378330680.879939) (5478579557842456 1378330681.293269) (5478582509328268 1378330682.163330) (5478583410670656 1378330682.429034) (5478586725512420 1378330683.406207) (5478588552386012 1378330683.944746) (5478589754458130 1378330684.299102) (5478592581802122 1378330685.132567) (5478594862063810 1378330685.804759) (5478597301415578 1378330686.523849) (5478599565506960 1378330687.191274) (5478601700389570 1378330687.820611) (5478602833425954 1378330688.154615) (5478605548581456 1378330688.955009) (5478608777383456 1378330689.906818) (5478611882764548 1378330690.822245) (5478614115803748 1378330691.480517) (5478614376076154 1378330691.557241) (5478614794667018 1378330691.680637) (5478615686684948 1378330691.943592) (5478616373877428 1378330692.146168) (5478618192914538 1378330692.682397) (5478620674607008 1378330693.413968) (5478623503378516 1378330694.247854) (5478624062709746 1378330694.412738) (5478626322720426 1378330695.078960) (5478627337827906 1378330695.378201) (5478630400603582 1378330696.281069) (5478632097192558 1378330696.781201) (5478632674221356 1378330696.951302) (5478634716696700 1378330697.553398) (5478636616953028 1378330698.113569) (5478639691496750 1378330699.019905) (5478642041015656 1378330699.712514) (5478642313604774 1378330699.792869) (5478644052955634 1378330700.305608) (5478644811457470 1378330700.529205) (5478645754249190 1378330700.807128) (5478647211132920 1378330701.236598) (5478648002341966 1378330701.469837) (5478649396807196 1378330701.880907) (5478650856106006 1378330702.311090) (5478653491766218 1378330703.088049) (5478655936241260 1378330703.808649) (5478656306553832 1378330703.917813) (5478658088202766 1378330704.443020) (5478659430986390 1378330704.838856) (5478662465666158 1378330705.733441) (5478664932153156 1378330706.460530) (5478667869208000 1378330707.326336) (5478670757659402 1378330708.177815) (5478670831770316 1378330708.199662) (5478672468446318 1378330708.682133) (5478673408217692 1378330708.959166) (5478676534355468 1378330709.880711) (5478677097857868 1378330710.046824) (5478679404492974 1378330710.726791) (5478679650561302 1378330710.799329) (5478683039676976 1378330711.798397) (5478685731520352 1378330712.591918) (5478688654848300 1378330713.453678) (5478689343273320 1378330713.656617) (5478692461596164 1378330714.575859) (5478695797486632 1378330715.559237) (5478697438640460 1378330716.043028) (5478698152992402 1378330716.253610) (5478700899031344 1378330717.063107) (5478703907848706 1378330717.950069) (5478705300155948 1378330718.360503) (5478708622460584 1378330719.339876) (5478711858912372 1378330720.293941) (5478712093849924 1378330720.363197) (5478714966290736 1378330721.209957) (5478715319901538 1378330721.314196) (5478715671201064 1378330721.417755) (5478716092088638 1378330721.541827) (5478717606145596 1378330721.988152) (5478718582383056 1378330722.275934) (5478721138776212 1378330723.029527) (5478722288085608 1378330723.368328) (5478722585159758 1378330723.455902) (5478722616596906 1378330723.465169) (5478723942425784 1378330723.856007) (5478726671121564 1378330724.660391) (5478727713136878 1378330724.967564) (5478727975026188 1378330725.044766) (5478728542055808 1378330725.211919) (5478731270469822 1378330726.016221) (5478734035970288 1378330726.831455) (5478736989795962 1378330727.702205) (5478737312260190 1378330727.797264) (5478739141261154 1378330728.336430) (5478739860999922 1378330728.548600) (5478740035052704 1378330728.599908) (5478740916863962 1378330728.859855) (5478743832491888 1378330729.719345) (5478744492205380 1378330729.913820) (5478745947999606 1378330730.342970) (5478749134767476 1378330731.282388) (5478752117350572 1378330732.161616) (5478754320016110 1378330732.810934) (5478755499406188 1378330733.158603) (5478757366832950 1378330733.709097) (5478758374301696 1378330734.006086) (5478759648410056 1378330734.381677) (5478762339107044 1378330735.174860) (5478762720100130 1378330735.287172) (5478765759654860 1378330736.183194) (5478769103093548 1378330737.168797) (5478770099652648 1378330737.462570) (5478771044352644 1378330737.741055) (5478773039275944 1378330738.329133) (5478773175714146 1378330738.369353) (5478774185450726 1378330738.667011) (5478776682282648 1378330739.403046) (5478779606818794 1378330740.265162) (5478781263228126 1378330740.753450) (5478782257746434 1378330741.046621) (5478782378075426 1378330741.082093) (5478783027027426 1378330741.273396) (5478785254187302 1378330741.929934) (5478786649735654 1378330742.341324) (5478787000441148 1378330742.444707) (5478789705370062 1378330743.242086) (5478789871269024 1378330743.290991) (5478793247791320 1378330744.286347) (5478795069923832 1378330744.823488) (5478797292733026 1378330745.478744) (5478799624861426 1378330746.166226) (5478800903517038 1378330746.543157) (5478802978106258 1378330747.154720) (5478805439983128 1378330747.880450) (5478806717528038 1378330748.257054) (5478808392769390 1378330748.750894) (5478810814122860 1378330749.464678) (5478813823473220 1378330750.351796) (5478816892632582 1378330751.256545) (5478816969687642 1378330751.279260) (5478818391093818 1378330751.698272) (5478820702461426 1378330752.379634) (5478821479177758 1378330752.608600) (5478822578693132 1378330752.932723) (5478823089167314 1378330753.083205) (5478823610658158 1378330753.236933) (5478826539570120 1378330754.100339) (5478829700281724 1378330755.032077) (5478833075319604 1378330756.026995) (5478834606207796 1378330756.478282) (5478837762755580 1378330757.408792) (5478839525742450 1378330757.928498) (5478842383605056 1378330758.770959) (5478845171498840 1378330759.592795) (5478846622561872 1378330760.020550) (5478848655879794 1378330760.619946) (5478851547474112 1378330761.472351) (5478854187863376 1378330762.250705) (5478857369936874 1378330763.188739) (5478859267466410 1378330763.748107) (5478861561075436 1378330764.424234) (5478861694392998 1378330764.463533) (5478864259346640 1378330765.219650) (5478866954357362 1378330766.014104) (5478866967905478 1378330766.018098) (5478869257324098 1378330766.692990) (5478871326837850 1378330767.303056) (5478872000807932 1378330767.501734) (5478872236949008 1378330767.571345) (5478872380906954 1378330767.613782) (5478873435043158 1378330767.924528) (5478874211793634 1378330768.153504) (5478877107546180 1378330769.007135) (5478877419191370 1378330769.099004) (5478878677006528 1378330769.469792) (5478880063548434 1378330769.878527) (5478882764242452 1378330770.674657) (5478883689684804 1378330770.947466) (5478884810777694 1378330771.277950) (5478886593550056 1378330771.803488) (5478886669988791 1378330771.826021) (5478889344973552 1378330772.614573) (5478891245161064 1378330773.174724) (5478891982241736 1378330773.392006) (5478894829948804 1378330774.231474) (5478896773141488 1378330774.804302) (5478898890627368 1378330775.428510) (5478901484334708 1378330776.193102) (5478904236103084 1378330777.004288) (5478904375518156 1378330777.045386) (5478907483927568 1378330777.961706) (5478908770970146 1378330778.341110) (5478911581964968 1378330779.169755) (5478913351148252 1378330779.691288) (5478916255707988 1378330780.547515) (5478916620594628 1378330780.655079) (5478920011444428 1378330781.654658) (5478922366363496 1378330782.348858) (5478924813025518 1378330783.070103) (5478927949421556 1378330783.994673) (5478930502214476 1378330784.747204) (5478930671335908 1378330784.797058) (5478931618009897 1378330785.076126) (5478932298101592 1378330785.276608) (5478934406139306 1378330785.898031) (5478937164641518 1378330786.711203) (5478938918467828 1378330787.228208) (5478941110594630 1378330787.874419) (5478942617096610 1378330788.318517) (5478945934796202 1378330789.296532) (5478947705286718 1378330789.818450) (5478947752072860 1378330789.832242) (5478949962049750 1378330790.483715) (5478950366889160 1378330790.603057) (5478951161436232 1378330790.837279) (5478951916329766 1378330791.059813) (5478954614968900 1378330791.855337) (5478955027343790 1378330791.976900) (5478956303459874 1378330792.353082) (5478957684422192 1378330792.760172) (5478958570702342 1378330793.021436) (5478959205138330 1378330793.208460) (5478961338079174 1378330793.837224) (5478964536962884 1378330794.780214) (5478965014490454 1378330794.920983) (5478965987710108 1378330795.207876) (5478968602248110 1378330795.978608) (5478970406342366 1378330796.510432) (5478973565831830 1378330797.441810) (5478974719560112 1378330797.781914) (5478977644123534 1378330798.644038) (5478978223056546 1378330798.814700) (5478979595336156 1378330799.219231) (5478981094425056 1378330799.661143) (5478982737817614 1378330800.145594) (5478983758610622 1378330800.446511) (5478985944774438 1378330801.090964) (5478988622042184 1378330801.880189) (5478988887519250 1378330801.958448) (5478989845478158 1378330802.240842) (5478993030474772 1378330803.179738) (5478995025944054 1378330803.767977) (5478997153404260 1378330804.395125) (5479000434817954 1378330805.362445) (5479001316239930 1378330805.622276) (5479003719432494 1378330806.330707) (5479003728095124 1378330806.333260) (5479006668017358 1378330807.199912) (5479007580892964 1378330807.469016) (5479008483448422 1378330807.735078) (5479011220107214 1378330808.541810) (5479011724563828 1378330808.690517) (5479014563593918 1378330809.527428) (5479015898351546 1378330809.920897) (5479018933755936 1378330810.815696) (5479019598195012 1378330811.011564) (5479021549037934 1378330811.586647) (5479023306013350 1378330812.104582) (5479023906550070 1378330812.281612) (5479024393308266 1378330812.425102) (5479025736753070 1378330812.821133) (5479026181596759 1378330812.952266) (5479028321062858 1378330813.582954) (5479029578965732 1378330813.953768) (5479032271177744 1378330814.747398) (5479033165170388 1378330815.010935) (5479033844770640 1378330815.211272) (5479035802474088 1378330815.788379) (5479037437567525 1378330816.270384) (5479040333241094 1378330817.123991) (5479042260934936 1378330817.692251) (5479044285532758 1378330818.289076) (5479045607326406 1378330818.678724) (5479048074281048 1378330819.405951) (5479050501083884 1378330820.121341) (5479051619896554 1378330820.451153) (5479054262179924 1378330821.230065) (5479056297110882 1378330821.829936) (5479057691779900 1378330822.241067) (5479060060990560 1378330822.939480) (5479060505606784 1378330823.070547) (5479062994250664 1378330823.804168) (5479063825311934 1378330824.049154) (5479066015853394 1378330824.694898) (5479069101790702 1378330825.604593) (5479069138635872 1378330825.615454) (5479070159060846 1378330825.916262) (5479071851550596 1378330826.415187) (5479073128158242 1378330826.791515) (5479075388195720 1378330827.457745) (5479075989979238 1378330827.635143) (5479077951790578 1378330828.213460) (5479079485670266 1378330828.665628) (5479080578219518 1378330828.987698) (5479083801848130 1378330829.937982) (5479085179209780 1378330830.344011) (5479087344780254 1378330830.982394) (5479089436964652 1378330831.599143) (5479092611576612 1378330832.534978) (5479095636359200 1378330833.426645) (5479097663289056 1378330834.024158) (5479100799416500 1378330834.948649) (5479103344105870 1378330835.698791) (5479104872164507 1378330836.149243) (5479105738008394 1378330836.404483) (5479108394744150 1378330837.187654) (5479109140348650 1378330837.407449) (5479109828133364 1378330837.610199) (5479111592426558 1378330838.130291) (5479113988307472 1378330838.836566) (5479114151638066 1378330838.884713) (5479116423787134 1378330839.554514) (5479119674861406 1378330840.512889) (5479121568258098 1378330841.071039) (5479124901333262 1378330842.053587) (5479125188550736 1378330842.138255) (5479127210781094 1378330842.734383) (5479128438685212 1378330843.096353) (5479130233300642 1378330843.625383) (5479132700995984 1378330844.352828) (5479133139175862 1378330844.481997) (5479133816393048 1378330844.681632) (5479135688680424 1378330845.233559) (5479136353300200 1378330845.429480) (5479138532987654 1378330846.072024) (5479138560698708 1378330846.080193) (5479139558000978 1378330846.374185) (5479142431528098 1378330847.221265) (5479143670946332 1378330847.586629) (5479144527640372 1378330847.839172) (5479145270525080 1378330848.058165) (5479145707256628 1378330848.186908) (5479148612629752 1378330849.043375) (5479150361996290 1378330849.559065) (5479151397204534 1378330849.864232) (5479152381799254 1378330850.154478) (5479152926551836 1378330850.315064) (5479154164805408 1378330850.680085) (5479156404449372 1378330851.340304) (5479158800104264 1378330852.046512) (5479162023798572 1378330852.996816) (5479162771222970 1378330853.217147) (5479165999780340 1378330854.168885) (5479167795697018 1378330854.698298) (5479168043341186 1378330854.771300) (5479170281640270 1378330855.431123) (5479172193508126 1378330855.994717) (5479174087827874 1378330856.553138) (5479174936045322 1378330856.803182) (5479178052153406 1378330857.721771) (5479179879411130 1378330858.260423) (5479182618301196 1378330859.067813) (5479183393810676 1378330859.296423) (5479185374055590 1378330859.880174) (5479186822165622 1378330860.307058) (5479187353049008 1378330860.463556) (5479187517850434 1378330860.512137) (5479187547891040 1378330860.520993) (5479189130461984 1378330860.987515) (5479191886762264 1378330861.800037) (5479194462570950 1378330862.559353) (5479196146908000 1378330863.055874) (5479198813381910 1378330863.841916) (5479200965966772 1378330864.476471) (5479203072255204 1378330865.097378) (5479204621945336 1378330865.554207) (5479205814635270 1378330865.905796) (5479207184208004 1378330866.309529) (5479210370061580 1378330867.248678) (5479211151715044 1378330867.479099) (5479212795793196 1378330867.963753) (5479213734860224 1378330868.240578) (5479214030110988 1378330868.327613) (5479217145603382 1378330869.246021) (5479218889267398 1378330869.760031) (5479221992411664 1378330870.674799) (5479225013189112 1378330871.565285) (5479227474277718 1378330872.290783) (5479228609004028 1378330872.625285) (5479229333028274 1378330872.838718) (5479231559934186 1378330873.495182) (5479232078145238 1378330873.647944) (5479232303791788 1378330873.714461) (5479233980346290 1378330874.208689) (5479234918659580 1378330874.485291) (5479236781041142 1378330875.034298) (5479237947034163 1378330875.378017) (5479238119091838 1378330875.428738) (5479240981817632 1378330876.272633) (5479244029811756 1378330877.171143) (5479244773628626 1378330877.390410) (5479246197174158 1378330877.810054) (5479248566279946 1378330878.508436) (5479250341274878 1378330879.031682) (5479253581621214 1378330879.986894) (5479253676882958 1378330880.014976) (5479256540956810 1378330880.859269) (5479257072636008 1378330881.016001) (5479257906492834 1378330881.261811) (5479258276288258 1378330881.370822) (5479261355303140 1378330882.278477) (5479264683051806 1378330883.259454) (5479266243336414 1378330883.719406) (5479269145019146 1378330884.574785) (5479271959590528 1378330885.404485) (5479274077768590 1378330886.028897) (5479277439261108 1378330887.019822) (5479278662366456 1378330887.380378) (5479279417278750 1378330887.602916) (5479280991921584 1378330888.067101) (5479281592527070 1378330888.244152) (5479283570297372 1378330888.827173) (5479285680704630 1378330889.449294) (5479287383773504 1378330889.951337) (5479290301320670 1378330890.811393) (5479291012539394 1378330891.021051) (5479294004697238 1378330891.903101) (5479294538822458 1378330892.060554) (5479296284038650 1378330892.575022) (5479297116478040 1378330892.820414) (5479299850513122 1378330893.626373) (5479300662983946 1378330893.865879) (5479301510755562 1378330894.115791) (5479304733775090 1378330895.065896) (5479304933202676 1378330895.124685) (5479306875495872 1378330895.697248) (5479307869531408 1378330895.990277) (5479309512094944 1378330896.474484) (5479310098398984 1378330896.647319) (5479311614422070 1378330897.094223) (5479312038183356 1378330897.219143) (5479313685279866 1378330897.704686) (5479315391959770 1378330898.207793) (5479316181094890 1378330898.440420) (5479319260482038 1378330899.348184) (5479322254478842 1378330900.230776) (5479325047230580 1378330901.054044) (5479328329308754 1378330902.021559) (5479331418384108 1378330902.932179) (5479332054110950 1378330903.119583) (5479333161061088 1378330903.445897) (5479333201858120 1378330903.457924) (5479336090088174 1378330904.309337) (5479337043234366 1378330904.590313) (5479338271630166 1378330904.952428) (5479341659955952 1378330905.951263) (5479342812377196 1378330906.290982) (5479343624721916 1378330906.530451) (5479346776617982 1378330907.459590) (5479348307193212 1378330907.910784) (5479351679964388 1378330908.905034) (5479352002119582 1378330909.000001) (5479353102050912 1378330909.324247) (5479355983662314 1378330910.173709) (5479356746250872 1378330910.398510) (5479357459793122 1378330910.608854) (5479359350203432 1378330911.166122) (5479360953718070 1378330911.638818) (5479363526980072 1378330912.397383) (5479366126288368 1378330913.163626) (5479367435201132 1378330913.549476) (5479367925148102 1378330913.693906) (5479369066801522 1378330914.030451) (5479370210707024 1378330914.367660) (5479370806042868 1378330914.543157) (5479372788122628 1378330915.127449) (5479374027917336 1378330915.492925) (5479375936548552 1378330916.055565) (5479378020604410 1378330916.669918) (5479379229550374 1378330917.026300) (5479380468265216 1378330917.391457) (5479382346429034 1378330917.945116) (5479382559959182 1378330918.008062) (5479384647473068 1378330918.623435) (5479386333843284 1378330919.120555) (5479386923864494 1378330919.294485) (5479389309630104 1378330919.997779) (5479390682889194 1378330920.402598) (5479393920580378 1378330921.357028) (5479396071686180 1378330921.991147) (5479399322971532 1378330922.949584) (5479399689983444 1378330923.057775) (5479402925029494 1378330924.011425) (5479403431805784 1378330924.160816) (5479404517668282 1378330924.480914) (5479404694759840 1378330924.533119) (5479405568256118 1378330924.790614) (5479408228726462 1378330925.574887) (5479410612381768 1378330926.277558) (5479411784230944 1378330926.623004) (5479412216515070 1378330926.750436) (5479412443944614 1378330926.817479) (5479412491200628 1378330926.831410) (5479413289508694 1378330927.066741) (5479415712366790 1378330927.780969) (5479416221185002 1378330927.930962) (5479417221594796 1378330928.225870) (5479419481411282 1378330928.892035) (5479420376818842 1378330929.155990) (5479420684395652 1378330929.246659) (5479421702955642 1378330929.546918) (5479422454831710 1378330929.768561) (5479423558275258 1378330930.093843) (5479426148108808 1378330930.857293) (5479427352635188 1378330931.212372) (5479427909477600 1378330931.376521) (5479431108218748 1378330932.319470) (5479432391228128 1378330932.697685) (5479433824469194 1378330933.120186) (5479436910879562 1378330934.030020) (5479440199230524 1378330934.999384) (5479442723327606 1378330935.743456) (5479443718157338 1378330936.036719) (5479445218029854 1378330936.478862) (5479445294779778 1378330936.501487) (5479448115524304 1378330937.333006) (5479449564132180 1378330937.760037) (5479451558660570 1378330938.347999) (5479453149671064 1378330938.817009) (5479454114409538 1378330939.101401) (5479456621354658 1378330939.840417) (5479457983069702 1378330940.241833) (5479461027895544 1378330941.139409) (5479462876135544 1378330941.684246) (5479465616133214 1378330942.491963) (5479468961899126 1378330943.478252) (5479468969017790 1378330943.480350) (5479472353625778 1378330944.478089) (5479473661833450 1378330944.863732) (5479474597364054 1378330945.139515) (5479477422698902 1378330945.972388) (5479478808795050 1378330946.380991) (5479479884312442 1378330946.698040) (5479481696616356 1378330947.232284) (5479483499175680 1378330947.763656) (5479484656402970 1378330948.104791) (5479487175657016 1378330948.847435) (5479488277109694 1378330949.172129) (5479491083787298 1378330949.999502) (5479492210339524 1378330950.331595) (5479493207933914 1378330950.625673) (5479495767360422 1378330951.380160) (5479498173695582 1378330952.089517) (5479500195857924 1378330952.685624) (5479500977950658 1378330952.916175) (5479503692870770 1378330953.716499) (5479505135063678 1378330954.141639) (5479505646545526 1378330954.292417) (5479506159604490 1378330954.443660) (5479506392868698 1378330954.512424) (5479507038892828 1378330954.702864) (5479510019268926 1378330955.581441) (5479513027911526 1378330956.468350) (5479513366902840 1378330956.568280) (5479513785328132 1378330956.691627) (5479516140082358 1378330957.385778) (5479516451831750 1378330957.477678) (5479517714889462 1378330957.850012) (5479519152708254 1378330958.273862) (5479521169052992 1378330958.868255) (5479523256990630 1378330959.483752) (5479525677301566 1378330960.197229) (5479526882222508 1378330960.552424) (5479527619021004 1378330960.769623) (5479528455366664 1378330961.016167) (5479529457833636 1378330961.311681) (5479530049721838 1378330961.486162) (5479532257862088 1378330962.137094) (5479534764889370 1378330962.876134) (5479537661007152 1378330963.729872) (5479538199234894 1378330963.888535) (5479539868106280 1378330964.380497) (5479542899311914 1378330965.274057) (5479545761211878 1378330966.117709) (5479548126516688 1378330966.814971) (5479550172844376 1378330967.418202) (5479551088306582 1378330967.688069) (5479552394438954 1378330968.073100) (5479553674657818 1378330968.450492) (5479555180281994 1378330968.894331) (5479557568563382 1378330969.598366) (5479560440808548 1378330970.445067) (5479562272861106 1378330970.985133) (5479565191096398 1378330971.845391) (5479568190669328 1378330972.729627) (5479569461067606 1378330973.104124) (5479570460300228 1378330973.398685) (5479573410437618 1378330974.268348) (5479575129765530 1378330974.775184) (5479577860863292 1378330975.580277) (5479578663594698 1378330975.816912) (5479580903329798 1378330976.477157) (5479581498124982 1378330976.652495) (5479583407897238 1378330977.215472) (5479584446166364 1378330977.521540) (5479585511569472 1378330977.835608) (5479586357866166 1378330978.085085) (5479586799226422 1378330978.215192) (5479588953280944 1378330978.850180) (5479589472430794 1378330979.003219) (5479590823713678 1378330979.401560) (5479592286248974 1378330979.832697) (5479595105764398 1378330980.663854) (5479596040160584 1378330980.939302) (5479597190222740 1378330981.278326) (5479599217898156 1378330981.876058) (5479602324818012 1378330982.791939) (5479604528172940 1378330983.441460) (5479604784841568 1378330983.517122) (5479607665876218 1378330984.366415) (5479609156780355 1378330984.805914) (5479610085063250 1378330985.079560) (5479613226789032 1378330986.005701) (5479614179609588 1378330986.286580) (5479615666237506 1378330986.724819) (5479616638157578 1378330987.011328) (5479619266990404 1378330987.786275) (5479619415954714 1378330987.830187) (5479620409896212 1378330988.123189) (5479621403004678 1378330988.415945) (5479624355483128 1378330989.286298) (5479624917047546 1378330989.451840) (5479625590469524 1378330989.650356) (5479626683082116 1378330989.972444) (5479627055372978 1378330990.082191) (5479628902533444 1378330990.626710) (5479630687566748 1378330991.152915) (5479633778413936 1378330992.064058) (5479636229122504 1378330992.786495) (5479639353401620 1378330993.707493) (5479641033539934 1378330994.202776) (5479643345337744 1378330994.884264) (5479644790690630 1378330995.310336) (5479647102468976 1378330995.991819) (5479647236223582 1378330996.031248) (5479648570720786 1378330996.424641) (5479650504372686 1378330996.994657) (5479650734190076 1378330997.062404) (5479651200901030 1378330997.199984) (5479652756254780 1378330997.658483) (5479654397056928 1378330998.142170) (5479654409503104 1378330998.145839) (5479655932843330 1378330998.594900) (5479656710723778 1378330998.824210) (5479659926386710 1378330999.772146) (5479661069000954 1378331000.108974) (5479662755991846 1378331000.606278) (5479664886326328 1378331001.234273) (5479667606927702 1378331002.036272) (5479669067339970 1378331002.466782) (5479672139136824 1378331003.372309) (5479673057921782 1378331003.643155) (5479676429580818 1378331004.637077) (5479678845504206 1378331005.349261) (5479678920614584 1378331005.371402) (5479680141859802 1378331005.731409) (5479681963724710 1378331006.268472) (5479682755694334 1378331006.501935) (5479685331361844 1378331007.261209) (5479687404101218 1378331007.872226) (5479689460538696 1378331008.478437) (5479692842115696 1378331009.475283) (5479695949947250 1378331010.391432) (5479696771160896 1378331010.633515) (5479699693709274 1378331011.495045) (5479702664183440 1378331012.370703) (5479703718929690 1378331012.681629) (5479706145318440 1378331013.396897) (5479707628740199 1378331013.834191) (5479709758592118 1378331014.462044) (5479711681855278 1378331015.028998) (5479714067207140 1378331015.732169) (5479717083797972 1378331016.621422) (5479719568010302 1378331017.353736) (5479722569187692 1378331018.238445) (5479724841947322 1378331018.908425) (5479727776260066 1378331019.773423) (5479730403231774 1378331020.547821) (5479732901762548 1378331021.284356) (5479733076066992 1378331021.335738) (5479733449778246 1378331021.445903) (5479735846623156 1378331022.152463) (5479736181257012 1378331022.251108) (5479738499488480 1378331022.934494) (5479740671242900 1378331023.574699) (5479742079772300 1378331023.989916) (5479743775178696 1378331024.489700) (5479746687725370 1378331025.348282) (5479748683286690 1378331025.936547) (5479751373356882 1378331026.729546) (5479752255513146 1378331026.989594) (5479754901042930 1378331027.769463) (5479758039855966 1378331028.694745) (5479760972353978 1378331029.559208) (5479761792876512 1378331029.801087) (5479762921543980 1378331030.133804) (5479763950584930 1378331030.437152) (5479766677661656 1378331031.241060) (5479768931099774 1378331031.905344) (5479770488213594 1378331032.364362) (5479771951295736 1378331032.795660) (5479773927179174 1378331033.378125) (5479775802671084 1378331033.930996) (5479778867016700 1378331034.834326) (5479779396860070 1378331034.990517) (5479781507580214 1378331035.612730) (5479782948005710 1378331036.037349) (5479784921123178 1378331036.618999) (5479785726897016 1378331036.856531) (5479787016505320 1378331037.236691) (5479789871447028 1378331038.078292) (5479791640579670 1378331038.599809) (5479792303444622 1378331038.795213) (5479795666817942 1378331039.786693) (5479798042809368 1378331040.487105) (5479798126186250 1378331040.511683) (5479801099000910 1378331041.388031) (5479801726543806 1378331041.573023) (5479803220092252 1378331042.013302) (5479803828900120 1378331042.192771) (5479804565259148 1378331042.409840) (5479804713509026 1378331042.453542) (5479806740633990 1378331043.051113) (5479808716993454 1378331043.633718) (5479811787484510 1378331044.538860) (5479811806933480 1378331044.544593) (5479813171762118 1378331044.946927) (5479814775235208 1378331045.419610) (5479816017883204 1378331045.785927) (5479817877530102 1378331046.334127) (5479820746751342 1378331047.179937) (5479822349597558 1378331047.652436) (5479825546828290 1378331048.594939) (5479828291685070 1378331049.404087) (5479830035731322 1378331049.918210) (5479830431247898 1378331050.034803) (5479830625739756 1378331050.092137) (5479830648188774 1378331050.098754) (5479833803502572 1378331051.028901) (5479835445791074 1378331051.513026) (5479836812315352 1378331051.915860) (5479839083689610 1378331052.585433) (5479840093703284 1378331052.883172) (5479842284788276 1378331053.529076) (5479845504217982 1378331054.478122) (5479845727481064 1378331054.543937) (5479847799343544 1378331055.154696) (5479848184945186 1378331055.268366) (5479849180601424 1378331055.561873) (5479850981919962 1378331056.092879) (5479853272149472 1378331056.768009) (5479856647991776 1378331057.763165) (5479858709032242 1378331058.370733) (5479861913845050 1378331059.315471) (5479862199648106 1378331059.399722) (5479864665311752 1378331060.126568) (5479866601576580 1378331060.697354) (5479867808081174 1378331061.053016) (5479869249234602 1378331061.477850) (5479870181700420 1378331061.752729) (5479872013738654 1378331062.292791) (5479872524752050 1378331062.443431) (5479873924782206 1378331062.856142) (5479876007092834 1378331063.469980) (5479876944602212 1378331063.746346) (5479878812215446 1378331064.296895) (5479881535889334 1378331065.099799) (5479881748286678 1378331065.162411) (5479881779564128 1378331065.171631) (5479883254784782 1378331065.606507) (5479884793949500 1378331066.060234) (5479884832844922 1378331066.071699) (5479888057497290 1378331067.022286) (5479889513809244 1378331067.451588) (5479892125912760 1378331068.221603) (5479892298184844 1378331068.272386) (5479894765952826 1378331068.999853) (5479895567347420 1378331069.236093) (5479898718992594 1378331070.165159) (5479899780658786 1378331070.478124) (5479901645284738 1378331071.027792) (5479904825268230 1378331071.965211) (5479906303390774 1378331072.400942) (5479908946674458 1378331073.180149) (5479911768029496 1378331074.011848) (5479913549611782 1378331074.537036) (5479915214681362 1378331075.027877) (5479916609032974 1378331075.438914) (5479917613563084 1378331075.735037) (5479918156828964 1378331075.895184) (5479920254880642 1378331076.513663) (5479920879180982 1378331076.697699) (5479921621872138 1378331076.916635) (5479923971951628 1378331077.609408) (5479924270215056 1378331077.697332) (5479927302760216 1378331078.591288) (5479927673233804 1378331078.700499) (5479928585004572 1378331078.969277) (5479929134171435 1378331079.131165) (5479929471693316 1378331079.230662) (5479930189814236 1378331079.442355) (5479933289706062 1378331080.356163) (5479935577977674 1378331081.030717) (5479936676523182 1378331081.354554) (5479937562573374 1378331081.615750) (5479938479353504 1378331081.886005) (5479939406319432 1378331082.159263) (5479942416578572 1378331083.046649) (5479943372257082 1378331083.328371) (5479945471371616 1378331083.947163) (5479946030025472 1378331084.111847) (5479946500109046 1378331084.250421) (5479947051360754 1378331084.412923) (5479949655570922 1378331085.180612) (5479949915692368 1378331085.257292) (5479950840298984 1378331085.529854) (5479952651920746 1378331086.063897) (5479954155515106 1378331086.507138) (5479954583230838 1378331086.633222) (5479954674930700 1378331086.660255) (5479955295192292 1378331086.843100) (5479956242229772 1378331087.122274) (5479959201071908 1378331087.994503) (5479960310923378 1378331088.321673) (5479960318194676 1378331088.323817) (5479961718384428 1378331088.736575) (5479963290737582 1378331089.200085) (5479965742896478 1378331089.922950) (5479968280691660 1378331090.671059) (5479971378590678 1378331091.584280) (5479974675933058 1378331092.556295) (5479976477328514 1378331093.087323) (5479978071803972 1378331093.557354) (5479980922078864 1378331094.397579) (5479980937384568 1378331094.402091) (5479981779973154 1378331094.650475) (5479983791150308 1378331095.243344) (5479986791611626 1378331096.127842) (5479988332322272 1378331096.582024) (5479989456830196 1378331096.913515) (5479991767752574 1378331097.594745) (5479995088690028 1378331098.573715) (5479997627028062 1378331099.321985) (5480000617855820 1378331100.203642) (5480003179487032 1378331100.958779) (5480003328406020 1378331101.002678) (5480003680808286 1378331101.106562) (5480004613750100 1378331101.381581) (5480006907451398 1378331102.057735) (5480009486253556 1378331102.817933) (5480011845335940 1378331103.513360) (5480014746220802 1378331104.368504) (5480017409902457 1378331105.153724) (5480018641776070 1378331105.516864) (5480021028050537 1378331106.220307) (5480022854819823 1378331106.758816) (5480025777583794 1378331107.620409) (5480026764986329 1378331107.911483) (5480028771365781 1378331108.502937) (5480029032700226 1378331108.579976) (5480029268702320 1378331108.649546) (5480030954976431 1378331109.146638) (5480032556593651 1378331109.618774) (5480032953888272 1378331109.735899) (5480033011698930 1378331109.752934) (5480036109726606 1378331110.666193) (5480036248453340 1378331110.707088) (5480038824317834 1378331111.466420) (5480040443693600 1378331111.943791) (5480041995742998 1378331112.401315) (5480042163424752 1378331112.450745) (5480044575762458 1378331113.161872) (5480045418065274 1378331113.410172) (5480048193088672 1378331114.228214) (5480051485011214 1378331115.198630) (5480054462347822 1378331116.076311) (5480054473092970 1378331116.079478) (5480057813618852 1378331117.064223) (5480058148063241 1378331117.162813) (5480061077962340 1378331118.026510) (5480064272124128 1378331118.968108) (5480064499213441 1378331119.035051) (5480065315459765 1378331119.275670) (5480068352854036 1378331120.171055) (5480069146330521 1378331120.404961) (5480069728631660 1378331120.576616) (5480072552717840 1378331121.409121) (5480075407281344 1378331122.250610) (5480076149327320 1378331122.469355) (5480078874683464 1378331123.272756) (5480081843370157 1378331124.147887) (5480081892284926 1378331124.162306) (5480084950886323 1378331125.063943) (5480086025785845 1378331125.380810) (5480086563742900 1378331125.539392) (5480087473904346 1378331125.807696) (5480089570770700 1378331126.425826) (5480090234745285 1378331126.621557) (5480092669332533 1378331127.339242) (5480095910088722 1378331128.294576) (5480096192401596 1378331128.377798) (5480097331868312 1378331128.713698) (5480097806455569 1378331128.853600) (5480098021053956 1378331128.916861) (5480099961781008 1378331129.488963) (5480102030469380 1378331130.098785) (5480105309945139 1378331131.065533) (5480108098715278 1378331131.887627) (5480108689125456 1378331132.061673) (5480111686272920 1378331132.945193) (5480114809054420 1378331133.865749) (5480117379053526 1378331134.623352) (5480118304185002 1378331134.896069) (5480121460931903 1378331135.826637) (5480122798671763 1378331136.220986) (5480125511524042 1378331137.020700) (5480126544514430 1378331137.325213) (5480127376134461 1378331137.570364) (5480129797040203 1378331138.284016) (5480130617241566 1378331138.525801) (5480132943767693 1378331139.211631) (5480133326668757 1378331139.324505) (5480135025644341 1378331139.825341) (5480135914037548 1378331140.087228) (5480138994079034 1378331140.995185) (5480141331053716 1378331141.684096) (5480143942653865 1378331142.453962) (5480145075337247 1378331142.787863) (5480146285591658 1378331143.144630) (5480147482398282 1378331143.497433) (5480149231739149 1378331144.013117) (5480151007795502 1378331144.536676) (5480154152903555 1378331145.463813) (5480157505932217 1378331146.452243) (5480160747257785 1378331147.407745) (5480161821585307 1378331147.724443) (5480162873805070 1378331148.034624) (5480164652108702 1378331148.558845) (5480165513001093 1378331148.812625) (5480167697286905 1378331149.456524) (5480169211343023 1378331149.902849) (5480169849490970 1378331150.090967) (5480171577652301 1378331150.600406) (5480173808373849 1378331151.257995) (5480175183803336 1378331151.663454) (5480177046031065 1378331152.212415) (5480180235964936 1378331153.152766) (5480181423415336 1378331153.502812) (5480184073925015 1378331154.284148) (5480186806141824 1378331155.089571) (5480187328458205 1378331155.243543) (5480189539336505 1378331155.895282) (5480189794836305 1378331155.970600) (5480189996095995 1378331156.029929) (5480192479650921 1378331156.762049) (5480194299047302 1378331157.298384) (5480197303447335 1378331158.184042) (5480199671739501 1378331158.882185) (5480203051415630 1378331159.878470) (5480204875042220 1378331160.416052) (5480206410468904 1378331160.868676) (5480209495614331 1378331161.778138) (5480212307574165 1378331162.607067) (5480213910503463 1378331163.079590) (5480214240887200 1378331163.176983) (5480217217383423 1378331164.054416) (5480219245154933 1378331164.652178) (5480220597074522 1378331165.050706) (5480223420544270 1378331165.883029) (5480224056793104 1378331166.070587) (5480224433730636 1378331166.181704) (5480226008141943 1378331166.645819) (5480226478203373 1378331166.784388) (5480227340567088 1378331167.038602) (5480230550385025 1378331167.984815) (5480233756919289 1378331168.930060) (5480235922551673 1378331169.568461) (5480237116331355 1378331169.920372) (5480237947492677 1378331170.165388) (5480238996994522 1378331170.474767) (5480240837229281 1378331171.017245) (5480242299677969 1378331171.448356) (5480243226332946 1378331171.721523) (5480244326875914 1378331172.045948) (5480247000191840 1378331172.834008) (5480247903938659 1378331173.100421) (5480249175393116 1378331173.475229) (5480251290131112 1378331174.098627) (5480253950337033 1378331174.882822) (5480256773441256 1378331175.715037) (5480258652962631 1378331176.269095) (5480259756121844 1378331176.594293) (5480259906087203 1378331176.638501) (5480261230240591 1378331177.028844) (5480262653690038 1378331177.448459) (5480265008077962 1378331178.142502) (5480265631894487 1378331178.326395) (5480267569415510 1378331178.897552) (5480268005302004 1378331179.026046) (5480268035166626 1378331179.034849) (5480268484683210 1378331179.167361) (5480268633153858 1378331179.211128) (5480271648906768 1378331180.100134) (5480274447081660 1378331180.925000) (5480277426170210 1378331181.803198) (5480279996626362 1378331182.560935) (5480281834416588 1378331183.102692) (5480284915315130 1378331184.010902) (5480285477840592 1378331184.176727) (5480286062519432 1378331184.349083) (5480288241937598 1378331184.991548) (5480288555658216 1378331185.084029) (5480290265570226 1378331185.588089) (5480291932564624 1378331186.079498) (5480294611941502 1378331186.869344) (5480296367510030 1378331187.386863) (5480298687563262 1378331188.070785) (5480299012643900 1378331188.166615) (5480302357880576 1378331189.152748) (5480302894230304 1378331189.310856) (5480304295767756 1378331189.724012) (5480306471971432 1378331190.365529) (5480307632789878 1378331190.707724) (5480310893530648 1378331191.668948) (5480312385540662 1378331192.108774) (5480312645949764 1378331192.185539) (5480315382335954 1378331192.992191) (5480318429596044 1378331193.890484) (5480319643394208 1378331194.248296) (5480322438519512 1378331195.072264) (5480323118848146 1378331195.272816) (5480324268800294 1378331195.611807) (5480324471627906 1378331195.671598) (5480325291911490 1378331195.913407) (5480327952607678 1378331196.697746) (5480329678610768 1378331197.206550) (5480332966537096 1378331198.175789) (5480335184514728 1378331198.829620) (5480337289106346 1378331199.450027) (5480338379392252 1378331199.771429) (5480340349277690 1378331200.352126) (5480341278484498 1378331200.626045) (5480343765573838 1378331201.359207) (5480345641293030 1378331201.912145) (5480347034863126 1378331202.322952) (5480347447250272 1378331202.444518) (5480349116689032 1378331202.936647) (5480350759157888 1378331203.420826) (5480350763572566 1378331203.422127) (5480352422057768 1378331203.911028) (5480354688842052 1378331204.579247) (5480357838148288 1378331205.507622) (5480359727696128 1378331206.064637) (5480362289827864 1378331206.819920) (5480362814318740 1378331206.974533) (5480364782231448 1378331207.554649) (5480365131531230 1378331207.657618) (5480366064389120 1378331207.932612) (5480368635318610 1378331208.690490) (5480370682467000 1378331209.293963) (5480373304707420 1378331210.066966) (5480375727450188 1378331210.781160) (5480377637470262 1378331211.344209) (5480377812422728 1378331211.395783) (5480380176271044 1378331212.092615) (5480380552269394 1378331212.203454) (5480382327419492 1378331212.726746) (5480383523577004 1378331213.079358) (5480384535902854 1378331213.377779) (5480384614719012 1378331213.401013) (5480386769240752 1378331214.036139) (5480390093349778 1378331215.016043) (5480390152201874 1378331215.033392) (5480390559237522 1378331215.153381) (5480391877751190 1378331215.542062) (5480395077272324 1378331216.485240) (5480395912956310 1378331216.731589) (5480397278910695 1378331217.134255) (5480398848140270 1378331217.596844) (5480400134750096 1378331217.976120) (5480403096170684 1378331218.849109) (5480405522882884 1378331219.564473) (5480407114156214 1378331220.033560) (5480407371657032 1378331220.109468) (5480407801621406 1378331220.236216) (5480410587017466 1378331221.057315) (5480410670614276 1378331221.081958) (5480414008622018 1378331222.065960) (5480416585476170 1378331222.825584) (5480418370355750 1378331223.351744) (5480418642658928 1378331223.432015) (5480421168333134 1378331224.176552) (5480422340436002 1378331224.522072) (5480424102895676 1378331225.041623) (5480424880932518 1378331225.270978) (5480426208123716 1378331225.662217) (5480429244151354 1378331226.557200) (5480431161967704 1378331227.122547) (5480431383962144 1378331227.187988) (5480434487160420 1378331228.102772) (5480436843024422 1378331228.797250) (5480439023152950 1378331229.439924) (5480441298282330 1378331230.110603) (5480443212670758 1378331230.674941) (5480443338055720 1378331230.711902) (5480443957616656 1378331230.894541) (5480447262867632 1378331231.868887) (5480447930157574 1378331232.065596) (5480449216818468 1378331232.444887) (5480451467570776 1378331233.108380) (5480453720977546 1378331233.772655) (5480455662736876 1378331234.345061) (5480455786544986 1378331234.381558) (5480457472122186 1378331234.878445) (5480459639216592 1378331235.517277) (5480462807917328 1378331236.451369) (5480465436733858 1378331237.226311) (5480466673993204 1378331237.591039) (5480469800350580 1378331238.512649) (5480473018977672 1378331239.461459) (5480474518284572 1378331239.903436) (5480476310812962 1378331240.431850) (5480479212513374 1378331241.287234) (5480480534017546 1378331241.676797) (5480483835342788 1378331242.649985) (5480486557131018 1378331243.452334) (5480488329968394 1378331243.974944) (5480488891265604 1378331244.140407) (5480490001222388 1378331244.467608) (5480491707808988 1378331244.970688) (5480494508721464 1378331245.796361) (5480496068147454 1378331246.256060) (5480496398225998 1378331246.353363) (5480497393698186 1378331246.646815) (5480498860360325 1378331247.079169) (5480500897845464 1378331247.679793) (5480504075707900 1378331248.616587) (5480507134941992 1378331249.518410) (5480507320686294 1378331249.573164) (5480508323590814 1378331249.868808) (5480510409639718 1378331250.483749) (5480513189580264 1378331251.303240) (5480514497843034 1378331251.688899) (5480515124457406 1378331251.873617) (5480516169396066 1378331252.181651) (5480516373231498 1378331252.241739) (5480519110723478 1378331253.048717) (5480519769037666 1378331253.242780) (5480520614504276 1378331253.492012) (5480520951425338 1378331253.591332) (5480523438344892 1378331254.324445) (5480523761267278 1378331254.419638) (5480525187386678 1378331254.840040) (5480526032217836 1378331255.089085) (5480527554743252 1378331255.537906) (5480530066088404 1378331256.278219) (5480531553470960 1378331256.716680) (5480533149864316 1378331257.187277) (5480535177255560 1378331257.784926) (5480538276807258 1378331258.698634) (5480539683965004 1378331259.113446) (5480541864813336 1378331259.756332) (5480543743057876 1378331260.310015) (5480544964910844 1378331260.670201) (5480545010458638 1378331260.683628) (5480547748099878 1378331261.490650) (5480550977081664 1378331262.442512) (5480554095731850 1378331263.361851) (5480554105963504 1378331263.364866) (5480556611130050 1378331264.103358) (5480558512043870 1378331264.663723) (5480558661164810 1378331264.707682) (5480559305777620 1378331264.897705) (5480562556443796 1378331265.855960) (5480562734805290 1378331265.908539) (5480565938049126 1378331266.852814) (5480566531959018 1378331267.027891) (5480568318745386 1378331267.554613) (5480570980246814 1378331268.339190) (5480571304729282 1378331268.434843) (5480573696112744 1378331269.139793) (5480574934010084 1378331269.504709) (5480577823197688 1378331270.356404) (5480581138013330 1378331271.333570) (5480582463417956 1378331271.724282) (5480582617610728 1378331271.769736) (5480584548206632 1378331272.338851) (5480585062123280 1378331272.490347) (5480588060478160 1378331273.374224) (5480590243813014 1378331274.017843) (5480593303991174 1378331274.919945) (5480596186451938 1378331275.769657) (5480598706898008 1378331276.512652) (5480598959025270 1378331276.586976) (5480601828544768 1378331277.432874) (5480603419009670 1378331277.901723) (5480603840388586 1378331278.025940) (5480604636818984 1378331278.260717) (5480606618895624 1378331278.845008) (5480607255447440 1378331279.032656) (5480609763714268 1378331279.772061) (5480611671055270 1378331280.334320) (5480611891694357 1378331280.399361) (5480612802456372 1378331280.667843) (5480613965887344 1378331281.010808) (5480616994199310 1378331281.903515) (5480619570541276 1378331282.662988) (5480621680508696 1378331283.284979) (5480623001677932 1378331283.674443) (5480623465405462 1378331283.811144) (5480625752347608 1378331284.485306) (5480626258177686 1378331284.634417) (5480627316873996 1378331284.946508) (5480629249147638 1378331285.516117) (5480632568129308 1378331286.494511) (5480633196235392 1378331286.679668) (5480635246736146 1378331287.284130) (5480636018775098 1378331287.511717) (5480637375199726 1378331287.911574) (5480638213468468 1378331288.158685) (5480639922361704 1378331288.662445) (5480641356265584 1378331289.085141) (5480644612570796 1378331290.045058) (5480645140151210 1378331290.200582) (5480646979607328 1378331290.742831) (5480647349797212 1378331290.851957) (5480648933093860 1378331291.318693) (5480649256146806 1378331291.413925) (5480650218117068 1378331291.697502) (5480652846216556 1378331292.472232) (5480654320330586 1378331292.906782) (5480656633461376 1378331293.588663) (5480657908545976 1378331293.964542) (5480660125312230 1378331294.618016) (5480660339732338 1378331294.681224) (5480662149587350 1378331295.214747) (5480663526630708 1378331295.620682) (5480664552907924 1378331295.923215) (5480666372814688 1378331296.459700) (5480666468408102 1378331296.487880) (5480668677937898 1378331297.139221) (5480670073863564 1378331297.550722) (5480672365586654 1378331298.226293) (5480674653371004 1378331298.900703) (5480675797869212 1378331299.238086) (5480675832697290 1378331299.248353) (5480677771462662 1378331299.819876) (5480677883449892 1378331299.852889) (5480678178500051 1378331299.939866) (5480680771205584 1378331300.704162) (5480684026291291 1378331301.663720) (5480685405417171 1378331302.070268) (5480688561890794 1378331303.000757) (5480691588534024 1378331303.892972) (5480693763090766 1378331304.534004) (5480696834602860 1378331305.439446) (5480699583220830 1378331306.249704) (5480701239537494 1378331306.737965) (5480703728511370 1378331307.471682) (5480706561527514 1378331308.306819) (5480706976226696 1378331308.429067) (5480710345905088 1378331309.422405) (5480713051971802 1378331310.220119) (5480715672501208 1378331310.992618) (5480717827222052 1378331311.627802) (5480720055439014 1378331312.284652) (5480723425085004 1378331313.277981) (5480726146166000 1378331314.080121) (5480726451556176 1378331314.170145) (5480727971376882 1378331314.618169) (5480729340078306 1378331315.021645) (5480732130807716 1378331315.844316) (5480732769158116 1378331316.032494) (5480735971913032 1378331316.976625) (5480736938450590 1378331317.261548) (5480738948470292 1378331317.854076) (5480741457120410 1378331318.593594) (5480743687583938 1378331319.251106) (5480744553514136 1378331319.506371) (5480746048575312 1378331319.947096) (5480747670580944 1378331320.425243) (5480749363110838 1378331320.924179) (5480751255426278 1378331321.482010) (5480753007422794 1378331321.998476) (5480754668143104 1378331322.488035) (5480756114369416 1378331322.914364) (5480759288872966 1378331323.850167) (5480762208005918 1378331324.710690) (5480762757204168 1378331324.872587) (5480765944753324 1378331325.812236) (5480767418368608 1378331326.246639) (5480769799048956 1378331326.948433) (5480772594825096 1378331327.772592) (5480773453095402 1378331328.025599) (5480775534017300 1378331328.639028) (5480776033302872 1378331328.786211) (5480778924765500 1378331329.638577) (5480782149348944 1378331330.589143) (5480783123306390 1378331330.876254) (5480783284556720 1378331330.923788) (5480784758365726 1378331331.358248) (5480786258100576 1378331331.800351) (5480788041123952 1378331332.325963) (5480789802738174 1378331332.845265) (5480792159747646 1378331333.540081) (5480795007862052 1378331334.379669) (5480796852357878 1378331334.923403) (5480800041273646 1378331335.863454) (5480802969033928 1378331336.726521) (5480805963130630 1378331337.609142) (5480809186133702 1378331338.559242) (5480810773957094 1378331339.027312) (5480813769079170 1378331339.910236) (5480814101993154 1378331340.008375) (5480817482550926 1378331341.004920) (5480820833507744 1378331341.992739) (5480821876986146 1378331342.300343) (5480822904907544 1378331342.603361) (5480825678905332 1378331343.421101) (5480826614403594 1378331343.696873) (5480829705384316 1378331344.608055) (5480832887003744 1378331345.545956) (5480834193194988 1378331345.931004) (5480837144762094 1378331346.801089) (5480839514500070 1378331347.499657) (5480839962862846 1378331347.631829) (5480839971047394 1378331347.634241) (5480840036607554 1378331347.653567) (5480842570555364 1378331348.400543) (5480844074262424 1378331348.843817) (5480845298052330 1378331349.204574) (5480846985581742 1378331349.702037) (5480850305147001 1378331350.680602) (5480852507772212 1378331351.329908) (5480853740165868 1378331351.693202) (5480856524791606 1378331352.514074) (5480859388477956 1378331353.358253) (5480860501246680 1378331353.686282) (5480863047209010 1378331354.436799) (5480863240715760 1378331354.493842) (5480863952011078 1378331354.703523) (5480865511612624 1378331355.163274) (5480866947624729 1378331355.586591) (5480870046102976 1378331356.499984) (5480873172532482 1378331357.421615) (5480874806993392 1378331357.903433) (5480877276229614 1378331358.631333) (5480879043446296 1378331359.152286) (5480879840061366 1378331359.387117) (5480881597990082 1378331359.905332) (5480882624737986 1378331360.208004) (5480884284808878 1378331360.697372) (5480886501039864 1378331361.350689) (5480888441468518 1378331361.922702) (5480891336436231 1378331362.776102) (5480894384355504 1378331363.674590) (5480896997088404 1378331364.444790) (5480898763730172 1378331364.965573) (5480900507174104 1378331365.479518) (5480900699032416 1378331365.536075) (5480903713140482 1378331366.424596) (5480905543658356 1378331366.964209) (5480908897500364 1378331367.952879) (5480911148824848 1378331368.616541) (5480912530728574 1378331369.023908) (5480912812784160 1378331369.107055) (5480912910286724 1378331369.135797) (5480913330322266 1378331369.259618) (5480915671461200 1378331369.949756) (5480918220872354 1378331370.701290) (5480918503136250 1378331370.784498) (5480918539933247 1378331370.795345) (5480920741312024 1378331371.444284) (5480924005491900 1378331372.406522) (5480924628723138 1378331372.590242) (5480927307197128 1378331373.379823) (5480929742824340 1378331374.097814) (5480932589591564 1378331374.937005) (5480932699544784 1378331374.969417) (5480934807340768 1378331375.590769) (5480935845628518 1378331375.896843) (5480938578974392 1378331376.702598) (5480940690533818 1378331377.325059) (5480943469877852 1378331378.144374) (5480946639550159 1378331379.078753) (5480946844616248 1378331379.139204) (5480947599057530 1378331379.361603) (5480949606142390 1378331379.953267) (5480950058677706 1378331380.086668) (5480951187278330 1378331380.419365) (5480954304712634 1378331381.338345) (5480954989957542 1378331381.540346) (5480958055580752 1378331382.444053) (5480959223190442 1378331382.788250) (5480961594578252 1378331383.487304) (5480964726890310 1378331384.410670) (5480967055761382 1378331385.097191) (5480967593634624 1378331385.255750) (5480970422444756 1378331386.089647) (5480970937540132 1378331386.241490) (5480971868989496 1378331386.516069) (5480974713953018 1378331387.354728) (5480976900579098 1378331387.999318) (5480979141096682 1378331388.659794) (5480981038366892 1378331389.219085) (5480982610356594 1378331389.682487) (5480984665645494 1378331390.288360) (5480985295652812 1378331390.474078) (5480987253455194 1378331391.051213) (5480990452379542 1378331391.994215) (5480993054923550 1378331392.761412) (5480994602548454 1378331393.217632) (5480997415651724 1378331394.046899) (5480998441870392 1378331394.349415) (5481001485708772 1378331395.246700) (5481001894337356 1378331395.367158) (5481003672629616 1378331395.891376) (5481005634042220 1378331396.469575) (5481008463693332 1378331397.303720) (5481011775891392 1378331398.280114) (5481012094412760 1378331398.374010) (5481012135905306 1378331398.386241) (5481014063417844 1378331398.954447) (5481014761109404 1378331399.160118) (5481017159133298 1378331399.867025) (5481017250167048 1378331399.893860) (5481019192340276 1378331400.466388) (5481019884044564 1378331400.670294) (5481020702819304 1378331400.911658) (5481022270423848 1378331401.373768) (5481022692538292 1378331401.498202) (5481023571079286 1378331401.757184) (5481024734387400 1378331402.100113) (5481026480244678 1378331402.614769) (5481028805737052 1378331403.300295) (5481031086899952 1378331403.972752) (5481034333993418 1378331404.929954) (5481036457943508 1378331405.556067) (5481039346054994 1378331406.407446) (5481042345666830 1378331407.291693) (5481043432018000 1378331407.611935) (5481045660905466 1378331408.268983) (5481046852301006 1378331408.620191) (5481048587305612 1378331409.131648) (5481049646336184 1378331409.443837) (5481050002818754 1378331409.548923) (5481052184242026 1378331410.191979) (5481054036802262 1378331410.738090) (5481056916316144 1378331411.586934) (5481059442203642 1378331412.331533) (5481060360833950 1378331412.602334) (5481063530478230 1378331413.536705) (5481063721951176 1378331413.593148) (5481066897599780 1378331414.529289) (5481067812213686 1378331414.798905) (5481069982149130 1378331415.438575) (5481071577000900 1378331415.908716) (5481071615251334 1378331415.919992) (5481071971134332 1378331416.024902) (5481074849914996 1378331416.873530) (5481075126528498 1378331416.955071) (5481076477395026 1378331417.353290) (5481077824600530 1378331417.750429) (5481078189237644 1378331417.857919) (5481079823467678 1378331418.339669) (5481081820768362 1378331418.928448) (5481083651468646 1378331419.468115) (5481084329675928 1378331419.668042) (5481087660623424 1378331420.649963) (5481090691069900 1378331421.543300) (5481092089135476 1378331421.955432) (5481093197694316 1378331422.282220) (5481093737496446 1378331422.441347) (5481095209196756 1378331422.875186) (5481095227821812 1378331422.880676) (5481095538370646 1378331422.972222) (5481096034435968 1378331423.118456) (5481098008600110 1378331423.700414) (5481098335415616 1378331423.796755) (5481099929055838 1378331424.266540) (5481100008028846 1378331424.289820) (5481101859265180 1378331424.835541) (5481104933969892 1378331425.741924) (5481108115755222 1378331426.679874) (5481110531158444 1378331427.391904) (5481110857072934 1378331427.487979) (5481113982047784 1378331428.409182) (5481115464713960 1378331428.846253) (5481117960575582 1378331429.582001) (5481118219067648 1378331429.658201) (5481120298330974 1378331430.271142) (5481122795304292 1378331431.007218) (5481124536114756 1378331431.520386) (5481127215257202 1378331432.310163) (5481130132939968 1378331433.170259) (5481133235311406 1378331434.084799) (5481133634778104 1378331434.202556) (5481135092506658 1378331434.632276) (5481138452100700 1378331435.622641) (5481139246021848 1378331435.856679) (5481139315957316 1378331435.877295) (5481140213803934 1378331436.141968) (5481142146808450 1378331436.711794) (5481142725975680 1378331436.882524) (5481146031836572 1378331437.857050) (5481146270008884 1378331437.927260) (5481147086013968 1378331438.167808) (5481147648632852 1378331438.333661) (5481150007231782 1378331439.028946) (5481151516623260 1378331439.473895) (5481153243206006 1378331439.982870) (5481154793275578 1378331440.439810) (5481155957875674 1378331440.783119) (5481158791136304 1378331441.618329) (5481160283120988 1378331442.058147) (5481160661257200 1378331442.169616) (5481161887980472 1378331442.531239) (5481163003951812 1378331442.860213) (5481165471280974 1378331443.587550) (5481167200197132 1378331444.097212) (5481170010859986 1378331444.925760) (5481171181079976 1378331445.270726) (5481174150174416 1378331446.145976) (5481175986353798 1378331446.687259) (5481178612661774 1378331447.461461) (5481178899835422 1378331447.546116) (5481179296334224 1378331447.662999) (5481181672763792 1378331448.363540) (5481181860611922 1378331448.418915) (5481184703007502 1378331449.256817) (5481185379441182 1378331449.456221) (5481187543927584 1378331450.094284) (5481190931843490 1378331451.092998) (5481193956914730 1378331451.984751) (5481194338095368 1378331452.097118) (5481194418861714 1378331452.120926) (5481195080839826 1378331452.316069) (5481198021199444 1378331453.182850) (5481201184601851 1378331454.115380) (5481203363956002 1378331454.757826) (5481204721146174 1378331455.157908) (5481206113856928 1378331455.568462) (5481207340925114 1378331455.930186) (5481207747821346 1378331456.050133) (5481209241950326 1378331456.490584) (5481209893526964 1378331456.682660) (5481210533487332 1378331456.871312) (5481213327143664 1378331457.694846) (5481214205078554 1378331457.953650) (5481214436401834 1378331458.021841) (5481216999464514 1378331458.777400) (5481218141140144 1378331459.113951) (5481220394321564 1378331459.778160) (5481223390681052 1378331460.661449) (5481225727488914 1378331461.350310) (5481227359561580 1378331461.831424) (5481227425460542 1378331461.850850) (5481229345502474 1378331462.416854) (5481229664010096 1378331462.510745) (5481232217620360 1378331463.263517) (5481234136932354 1378331463.829306) (5481237170652920 1378331464.723608) (5481239961909428 1378331465.546435) (5481241151742568 1378331465.897183) (5481241240773328 1378331465.923428) (5481242500960430 1378331466.294915) (5481244410651277 1378331466.857867) (5481244703853660 1378331466.944299) (5481247658313003 1378331467.815236) (5481249713217869 1378331468.420996) (5481250237792591 1378331468.575634) (5481253196046614 1378331469.447689) (5481254603759936 1378331469.862665) (5481256257489861 1378331470.350164) (5481259328414123 1378331471.255433) (5481260231008419 1378331471.521506) (5481261316986406 1378331471.841638) (5481262294831197 1378331472.129894) (5481263692621640 1378331472.541945) (5481265127172404 1378331472.964832) (5481268132948431 1378331473.850897) (5481270633560744 1378331474.588046) (5481271724602720 1378331474.909671) (5481273486485228 1378331475.429051) (5481275324742020 1378331475.970946) (5481277398378301 1378331476.582227) (5481278614836514 1378331476.940824) (5481281663437952 1378331477.839512) (5481284517938664 1378331478.680982) (5481286496288546 1378331479.264175) (5481287932022485 1378331479.687411) (5481288875350433 1378331479.965492) (5481291918742049 1378331480.862645) (5481292821434275 1378331481.128747) (5481295080363091 1378331481.794651) (5481297639413659 1378331482.549026) (5481299498877832 1378331483.097172) (5481300523252115 1378331483.399145) (5481301093666830 1378331483.567296) (5481302280566009 1378331483.917178) (5481305433530643 1378331484.846632) (5481307233638835 1378331485.377281) (5481307914848984 1378331485.578093) (5481310645174784 1378331486.382958) (5481311811942342 1378331486.726906) (5481312850498947 1378331487.033059) (5481313880957958 1378331487.336826) (5481314004722572 1378331487.373310) (5481317105762350 1378331488.287456) (5481317873955238 1378331488.513910) (5481318133519830 1378331488.590426) (5481320328430023 1378331489.237458) (5481322073115470 1378331489.751769) (5481324530444402 1378331490.476158) (5481324584452432 1378331490.492078) (5481327763824374 1378331491.429317) (5481329393013632 1378331491.909581) (5481332757061796 1378331492.901260) (5481335407316056 1378331493.682520) (5481337129490438 1378331494.190196) (5481338930429910 1378331494.721089) (5481341678109635 1378331495.531070) (5481342390430441 1378331495.741053) (5481344221972863 1378331496.280969) (5481345395147145 1378331496.626805) (5481346967277293 1378331497.090249) (5481349222543438 1378331497.755073) (5481349380675259 1378331497.801689) (5481349420506406 1378331497.813430) (5481352101452326 1378331498.603739) (5481353502545368 1378331499.016763) (5481356664868694 1378331499.948975) (5481360006135936 1378331500.933938) (5481361563226825 1378331501.392949) (5481364221256497 1378331502.176502) (5481364302701569 1378331502.200511) (5481366253917958 1378331502.775704) (5481369499910286 1378331503.732581) (5481369717837659 1378331503.796824) (5481371590430741 1378331504.348840) (5481373087711552 1378331504.790219) (5481375703400899 1378331505.561291) (5481376535082852 1378331505.806460) (5481377262240763 1378331506.020817) (5481378512535142 1378331506.389388) (5481381363580547 1378331507.229839) (5481384161152018 1378331508.054528) (5481384381641152 1378331508.119525) (5481387332160147 1378331508.989300) (5481387516654233 1378331509.043687) (5481388651938160 1378331509.378354) (5481391728805477 1378331510.285375) (5481393643911175 1378331510.849923) (5481395444617749 1378331511.380749) (5481396067318882 1378331511.564313) (5481397097173581 1378331511.867901) (5481398598599100 1378331512.310502) (5481401642165500 1378331513.207707) (5481404103751189 1378331513.933351) (5481405175562330 1378331514.249307) (5481405445136055 1378331514.328774) (5481406391616637 1378331514.607784) (5481409728669784 1378331515.591504) (5481412987322702 1378331516.552114) (5481414022358688 1378331516.857229) (5481414971328040 1378331517.136974) (5481417517568500 1378331517.887572) (5481420166551701 1378331518.668459) (5481422228693199 1378331519.276352) (5481423617933710 1378331519.685882) (5481425592827403 1378331520.268055) (5481428798052962 1378331521.212916) (5481429961824016 1378331521.555979) (5481432852612318 1378331522.408147) (5481434840965873 1378331522.994288) (5481437789130279 1378331523.863369) (5481439716505859 1378331524.431536) (5481441756995707 1378331525.033046) (5481443970929793 1378331525.685684) (5481445211526342 1378331526.051397) (5481446674907220 1378331526.482783) (5481447108002129 1378331526.610453) (5481447302624918 1378331526.667826) (5481448858845426 1378331527.126579) (5481451786226841 1378331527.989534) (5481452080032079 1378331528.076144) (5481454333152380 1378331528.740335) (5481454890793688 1378331528.904720) (5481455015618898 1378331528.941517) (5481455552420895 1378331529.099760) (5481457145402378 1378331529.569350) (5481458481828642 1378331529.963312) (5481459650078646 1378331530.307697) (5481462082274084 1378331531.024677) (5481463189474895 1378331531.351065) (5481466158715788 1378331532.226360) (5481466539206380 1378331532.338523) (5481467769132128 1378331532.701090) (5481469811668324 1378331533.303203) (5481472733627730 1378331534.164560) (5481472883090242 1378331534.208619) (5481475792993798 1378331535.066421) (5481477968691004 1378331535.707789) (5481479228967686 1378331536.079303) (5481480803926916 1378331536.543581) (5481483815973758 1378331537.431493) (5481486180418834 1378331538.128501) (5481488699650492 1378331538.871139) (5481491045491686 1378331539.562663) (5481492188727780 1378331539.899674) (5481492971481892 1378331540.130420) (5481493274693500 1378331540.219803) (5481496136488834 1378331541.063424) (5481499349153458 1378331542.010476) (5481501601844284 1378331542.674540) (5481503732939464 1378331543.302760) (5481503969223032 1378331543.372413) (5481506750370104 1378331544.192260) (5481509677447868 1378331545.055125) (5481511298605004 1378331545.533021) (5481513471932107 1378331546.173690) (5481515253106914 1378331546.698758) (5481518326256331 1378331547.604683) (5481521089456905 1378331548.419239) (5481522383696809 1378331548.800764) (5481522461572607 1378331548.823721) (5481524962779528 1378331549.561045) (5481525576059587 1378331549.741832) (5481526891100218 1378331550.129489) (5481528642580023 1378331550.645803) (5481528842264374 1378331550.704667) (5481531167525846 1378331551.390124) (5481533798188304 1378331552.165610) (5481534588083174 1378331552.398461) (5481536368303826 1378331552.923247) (5481538349416049 1378331553.507254) (5481539873236098 1378331553.956457) (5481541253251833 1378331554.363267) (5481544481481552 1378331555.314908) (5481547122229456 1378331556.093367) (5481547625777700 1378331556.241807) (5481547961065274 1378331556.340645) (5481551272359930 1378331557.316772) (5481554556819624 1378331558.284989) (5481557340530806 1378331559.105592) (5481558751950578 1378331559.521660) (5481561346633608 1378331560.286539) (5481562507674924 1378331560.628800) (5481563567168184 1378331560.941124) (5481565544628508 1378331561.524055) (5481568387693344 1378331562.362154) (5481568847369222 1378331562.497660) (5481570751553458 1378331563.058989) (5481574039406634 1378331564.028206) (5481576937542471 1378331564.882540) (5481577319218151 1378331564.995053) (5481579946699621 1378331565.769601) (5481582343251229 1378331566.476073) (5481585085655986 1378331567.284500) (5481588447030004 1378331568.275389) (5481588594958802 1378331568.318997) (5481590227470101 1378331568.800240) (5481591528582117 1378331569.183792) (5481594066078076 1378331569.931813) (5481596168386858 1378331570.551547) (5481598092068489 1378331571.118623) (5481599117219148 1378331571.420825) (5481599305754708 1378331571.476402) (5481600660867812 1378331571.875872) (5481600966397412 1378331571.965938) (5481603571462512 1378331572.733878) (5481606940120836 1378331573.726916) (5481610166195026 1378331574.677921) (5481613410644372 1378331575.634343) (5481616181293874 1378331576.451095) (5481616221851752 1378331576.463051) (5481617600974668 1378331576.869599) (5481620043812178 1378331577.589716) (5481621144765804 1378331577.914263) (5481623152910464 1378331578.506239) (5481624574978424 1378331578.925446) (5481626197867180 1378331579.403853) (5481629158909735 1378331580.276730) (5481629991625456 1378331580.522204) (5481632308060994 1378331581.205060) (5481635242962074 1378331582.070231) (5481637733391066 1378331582.804378) (5481638381141020 1378331582.995326) (5481640997186964 1378331583.766503) (5481643923573228 1378331584.629164) (5481644802471350 1378331584.888252) (5481645199782616 1378331585.005374) (5481645381515268 1378331585.058947) (5481645418987560 1378331585.069993) (5481648123089084 1378331585.867128) (5481651143874318 1378331586.757617) (5481653192802844 1378331587.361615) (5481656539940392 1378331588.348308) (5481657382814732 1378331588.596776) (5481659990893532 1378331589.365605) (5481663107636208 1378331590.284381) (5481663614300002 1378331590.433738) (5481664688845454 1378331590.750501) (5481665876848702 1378331591.100709) (5481667578218620 1378331591.602251) (5481669008476628 1378331592.023873) (5481671190259460 1378331592.667035) (5481671892458060 1378331592.874033) (5481674684784882 1378331593.697176) (5481677340942428 1378331594.480177) (5481680106650294 1378331595.295472) (5481683473061404 1378331596.287847) (5481684710130460 1378331596.652519) (5481685445822698 1378331596.869392) (5481686199345914 1378331597.091521) (5481688330121792 1378331597.719647) (5481689208447310 1378331597.978565) (5481691755279922 1378331598.729339) (5481695020492600 1378331599.691882) (5481695711382162 1378331599.895547) (5481698661250102 1378331600.765131) (5481699373799908 1378331600.975181) (5481700582414032 1378331601.331466) (5481701569964594 1378331601.622583) (5481701765288372 1378331601.680161) (5481702818604360 1378331601.990666) (5481704087873660 1378331602.364830) (5481707210058758 1378331603.285210) (5481709493425744 1378331603.958318) (5481711301643146 1378331604.491357) (5481711852237394 1378331604.653665) (5481714794345020 1378331605.520961) (5481716810783276 1378331606.115381) (5481717350658234 1378331606.274530) (5481717948007464 1378331606.450620) (5481718041363628 1378331606.478140) (5481721168335672 1378331607.399932) (5481721541421548 1378331607.509912) (5481722332195706 1378331607.743023) (5481724753151826 1378331608.456690) (5481726860313752 1378331609.077854) (5481727016204704 1378331609.123809) (5481729460724590 1378331609.844422) (5481732761453863 1378331610.817434) (5481734043439580 1378331611.195348) (5481734431432244 1378331611.309723) (5481735941990663 1378331611.755016) (5481737011207712 1378331612.070208) (5481739062598681 1378331612.674931) (5481739217435208 1378331612.720575) (5481740939998727 1378331613.228365) (5481741345247645 1378331613.347828) (5481743931244780 1378331614.110146) (5481744728336098 1378331614.345118) (5481744878628231 1378331614.389422) (5481747271231865 1378331615.094732) (5481750301354734 1378331615.987973) (5481750758767013 1378331616.122812) (5481752544677722 1378331616.649276) (5481754892449564 1378331617.341369) (5481756438835482 1378331617.797224) (5481758915818026 1378331618.527407) (5481760548476350 1378331619.008694) (5481761078864800 1378331619.165045) (5481762306259308 1378331619.526865) (5481764692982826 1378331620.230441) (5481766734404884 1378331620.832226) (5481768095622220 1378331621.233495) (5481771309831498 1378331622.181003) (5481771999369238 1378331622.384270) (5481772617318124 1378331622.566434) (5481773383708094 1378331622.792356) (5481776309303528 1378331623.654784) (5481776334360660 1378331623.662170) (5481779424368884 1378331624.573065) (5481780903193246 1378331625.009004) (5481783081995920 1378331625.651286) (5481783602177415 1378331625.804629) (5481785844527096 1378331626.465645) (5481787559485873 1378331626.971194) (5481789512606418 1378331627.546948) (5481790692620621 1378331627.894801) (5481792276040766 1378331628.361573) (5481794573880118 1378331629.038947) (5481797489616542 1378331629.898469) (5481799686008997 1378331630.545937) (5481801444170352 1378331631.064220) (5481802268831629 1378331631.307320) (5481804040706962 1378331631.829646) (5481806051523992 1378331632.422409) (5481807237588962 1378331632.772046) (5481809228044004 1378331633.358807) (5481812386609723 1378331634.289911) (5481814861726914 1378331635.019545) (5481815230141327 1378331635.128148) (5481816951016132 1378331635.635440) (5481817694148688 1378331635.854506) (5481819087285174 1378331636.265185) (5481821748831242 1378331637.049775) (5481822127326936 1378331637.161350) (5481824118507516 1378331637.748325) (5481826425448716 1378331638.428382) (5481829563092620 1378331639.353319) (5481830847168964 1378331639.731848) (5481832587645624 1378331640.244919) (5481833879828398 1378331640.625837) (5481836823591604 1378331641.493621) (5481837257511410 1378331641.621535) (5481839954482428 1378331642.416568) (5481843036538458 1378331643.325118) (5481843080897672 1378331643.338195) (5481844314591828 1378331643.701872) ) core-113.00.00/src/time_stamp_counter_samples_at_60sec.sexp000066400000000000000000000532731256461075500235720ustar00rootroot00000000000000((5746042637364132 1378409525.980234) (5746062481975270 1378409531.830171) (5746258448845268 1378409589.598695) (5746458164313262 1378409648.472257) (5746458694967606 1378409648.628687) (5746503370878578 1378409661.798574) (5746587767804420 1378409686.677707) (5746618566868504 1378409695.756877) (5746712262173062 1378409723.377053) (5746812703637526 1378409752.985912) (5746973480344008 1378409800.380828) (5747022468978918 1378409814.822050) (5747078486989108 1378409831.335442) (5747135002653636 1378409847.995536) (5747175000513022 1378409859.786393) (5747353519642390 1378409912.411547) (5747530503660268 1378409964.584172) (5747673731580994 1378410006.805932) (5747875080762214 1378410066.161096) (5748027911203966 1378410111.213557) (5748220600393931 1378410168.015867) (5748290418105871 1378410188.597236) (5748446157618775 1378410234.507254) (5748626524895132 1378410287.677223) (5748704272306844 1378410310.596167) (5748834319796242 1378410348.932507) (5748954892147798 1378410384.475698) (5749055593667372 1378410414.161221) (5749060648528598 1378410415.651330) (5749081471975402 1378410421.789816) (5749130032336162 1378410436.104790) (5749245432374538 1378410470.123248) (5749374424436514 1378410508.148463) (5749463492948492 1378410534.404724) (5749463892908554 1378410534.522627) (5749579953177638 1378410568.735716) (5749677560935502 1378410597.509239) (5749854649249330 1378410649.712616) (5750021085962460 1378410698.776036) (5750074245436294 1378410714.446771) (5750132353850642 1378410731.576390) (5750319795868916 1378410786.831904) (5750372068272966 1378410802.241142) (5750496940099622 1378410839.051763) (5750661886977308 1378410887.675998) (5750734866478938 1378410909.189422) (5750902394620432 1378410958.574577) (5751060126737382 1378411005.071988) (5751166643606542 1378411036.471800) (5751271301755499 1378411067.323683) (5751454822814302 1378411121.423345) (5751535585401078 1378411145.231122) (5751596191207503 1378411163.096938) (5751737769369562 1378411204.832370) (5751787611248458 1378411219.525118) (5751816608590102 1378411228.073164) (5751875994311308 1378411245.579315) (5752068991390784 1378411302.472383) (5752115835207256 1378411316.281341) (5752271850783502 1378411362.272737) (5752420210944526 1378411406.007416) (5752548792038352 1378411443.911478) (5752593577597836 1378411457.113689) (5752794568839100 1378411516.363337) (5752920176562282 1378411553.390886) (5752985661448094 1378411572.694993) (5753104316882990 1378411607.673098) (5753209899560800 1378411638.797523) (5753296534795380 1378411664.336483) (5753337039668972 1378411676.276802) (5753363046703492 1378411683.943343) (5753404711023756 1378411696.225452) (5753573490047258 1378411745.979351) (5753720743104106 1378411789.387671) (5753822171026820 1378411819.287327) (5753827180092164 1378411820.763936) (5753944576489414 1378411855.370896) (5754065058273826 1378411890.887388) (5754228203765784 1378411938.980598) (5754404145721706 1378411990.846042) (5754585858224618 1378412044.412569) (5754612214026982 1378412052.181923) (5754696459170796 1378412077.016317) (5754878337550086 1378412130.631743) (5755008548690926 1378412169.016327) (5755211494492614 1378412228.842161) (5755402097752374 1378412285.029571) (5755513294810692 1378412317.809045) (5755534244909732 1378412323.984866) (5755713007260744 1378412376.681723) (5755893472884868 1378412429.880685) (5755945399965668 1378412445.188126) (5756053263487808 1378412476.984916) (5756224453408108 1378412527.449521) (5756233054787956 1378412529.985098) (5756334334925125 1378412559.841189) (5756463343741336 1378412597.871341) (5756530417409784 1378412617.643801) (5756615374644294 1378412642.688107) (5756782131883916 1378412691.846008) (5756874535982852 1378412719.085554) (5756958221089418 1378412743.754853) (5757062574143670 1378412774.516797) (5757227515810050 1378412823.139489) (5757329465992102 1378412853.193097) (5757500448282754 1378412903.596484) (5757581127938972 1378412927.379813) (5757603216285396 1378412933.891174) (5757792708098832 1378412989.750935) (5757835931845340 1378413002.492741) (5757844962092230 1378413005.154743) (5757852139526306 1378413007.270558) (5757948964218788 1378413035.813237) (5758132141571632 1378413089.811577) (5758146232545988 1378413093.965416) (5758151750680452 1378413095.592092) (5758167075109768 1378413100.109537) (5758198245206416 1378413109.298083) (5758316913718206 1378413144.280045) (5758494726482572 1378413196.696977) (5758572862445068 1378413219.730462) (5758587663451566 1378413224.093610) (5758689982715942 1378413254.256024) (5758840773743320 1378413298.707295) (5758901642317950 1378413316.650573) (5759104739696346 1378413376.521087) (5759204252513948 1378413405.856197) (5759355388176044 1378413450.409063) (5759365019168712 1378413453.248157) (5759525490372742 1378413500.553022) (5759716112807168 1378413556.746085) (5759764275628056 1378413570.943871) (5759918892622656 1378413616.522989) (5759936711307364 1378413621.775710) (5759974450743194 1378413632.900814) (5760066766086346 1378413660.114201) (5760199409605002 1378413699.215819) (5760381535926878 1378413752.904336) (5760584468153290 1378413812.726164) (5760755114209876 1378413863.030440) (5760931893254860 1378413915.142643) (5761097882634630 1378413964.074189) (5761142697062724 1378413977.284909) (5761241742113662 1378414006.482122) (5761363902005968 1378414042.493295) (5761563627022794 1378414101.369673) (5761747417746712 1378414155.548826) (5761870968378452 1378414191.969970) (5762008218441934 1378414232.429532) (5762093309878456 1378414257.513398) (5762213041485408 1378414292.808742) (5762392095330396 1378414345.591522) (5762560416075004 1378414395.210324) (5762562169305532 1378414395.727154) (5762690534490492 1378414433.567568) (5762833918643694 1378414475.835384) (5762876293704378 1378414488.327011) (5762904865241368 1378414496.749535) (5763028441067066 1378414533.178109) (5763170597429606 1378414575.083988) (5763360853186222 1378414631.168954) (5763462417823830 1378414661.108912) (5763481219991424 1378414666.651551) (5763574526133224 1378414694.157010) (5763665169153090 1378414720.877415) (5763712963387856 1378414734.966547) (5763910500327770 1378414793.197918) (5764058167781668 1378414836.728400) (5764218979567320 1378414884.133665) (5764227953964186 1378414886.779203) (5764299315145204 1378414907.815568) (5764306998074552 1378414910.080398) (5764418043063892 1378414942.815043) (5764555696408132 1378414983.393492) (5764725341833462 1378415033.402800) (5764827797120892 1378415063.605312) (5764874422555576 1378415077.349896) (5765032321527662 1378415123.896498) (5765084219275902 1378415139.195292) (5765140550533812 1378415155.801027) (5765182380729400 1378415168.132035) (5765196878605812 1378415172.405824) (5765257749353000 1378415190.349741) (5765382112384684 1378415227.010373) (5765469099096662 1378415252.652942) (5765470641061031 1378415253.107493) (5765656740129346 1378415307.967112) (5765691067345390 1378415318.086335) (5765729771561062 1378415329.495842) (5765851517796644 1378415365.385072) (5765926016077882 1378415387.346211) (5766116341069360 1378415443.451579) (5766163140194328 1378415457.247360) (5766217263326190 1378415473.202164) (5766228712272594 1378415476.577167) (5766425701457574 1378415534.647051) (5766439382671768 1378415538.680098) (5766531389925806 1378415565.802656) (5766657796268138 1378415603.065626) (5766821980285624 1378415651.464975) (5766884161988296 1378415669.795345) (5766979390982654 1378415697.867635) (5766987862732750 1378415700.364999) (5767005969703144 1378415705.702702) (5767024769280882 1378415711.244577) (5767148212615746 1378415747.634098) (5767209259591402 1378415765.629968) (5767401953877546 1378415822.433785) (5767453656753918 1378415837.675134) (5767621919124870 1378415887.276737) (5767709894877892 1378415913.210867) (5767912185856732 1378415972.843669) (5767973141464724 1378415990.812606) (5768096772410576 1378416027.257433) (5768175119702996 1378416050.353217) (5768267200456432 1378416077.497450) (5768442075928165 1378416129.048511) (5768579193471080 1378416169.469014) (5768708109615230 1378416207.471849) (5768727169749664 1378416213.090534) (5768805433623636 1378416236.161725) (5768977726627540 1378416286.951502) (5769021306832190 1378416299.798390) (5769109040272330 1378416325.661087) (5769201132252192 1378416352.808626) (5769202145747584 1378416353.107391) (5769248469274764 1378416366.762975) (5769343542357480 1378416394.789305) (5769372749088660 1378416403.399076) (5769430387974900 1378416420.390282) (5769561964081949 1378416459.177235) (5769748178255104 1378416514.070791) (5769837724084116 1378416540.467756) (5769843552293516 1378416542.185837) (5769891565775632 1378416556.339597) (5770045792557221 1378416601.803678) (5770088442224876 1378416614.376254) (5770233256333594 1378416657.065598) (5770333680875808 1378416686.669465) (5770499731588374 1378416735.619086) (5770650012607310 1378416779.920005) (5770769825538088 1378416815.239322) (5770927647493340 1378416861.763214) (5770948132716200 1378416867.801995) (5770976893303272 1378416876.280248) (5771146681133004 1378416926.331527) (5771261762847348 1378416960.256144) (5771317498807104 1378416976.686392) (5771348551746324 1378416985.840401) (5771407511161488 1378417003.220884) (5771601874496444 1378417060.516709) (5771797224065444 1378417118.103264) (5771990974430952 1378417175.218394) (5772133374611106 1378417217.196149) (5772179263019920 1378417230.723466) (5772251910069488 1378417252.138889) (5772391876514130 1378417293.399211) (5772399828627886 1378417295.743392) (5772493632328382 1378417323.395527) (5772687851887812 1378417380.648979) (5772736094710802 1378417394.870348) (5772779475591540 1378417407.658479) (5772789429786244 1378417410.592849) (5772883668390726 1378417438.373188) (5772995270234686 1378417471.271990) (5773014882016783 1378417477.053293) (5773139844734704 1378417513.890711) (5773224096060840 1378417538.726928) (5773291030189306 1378417558.458257) (5773358911194610 1378417578.468712) (5773400114307544 1378417590.614865) (5773580146457568 1378417643.686047) (5773748816764224 1378417693.407902) (5773891632614140 1378417735.508192) (5773896531867584 1378417736.952429) (5773979110154166 1378417761.295453) (5774129309429078 1378417805.572279) (5774180460201986 1378417820.650873) (5774225308764420 1378417833.871656) (5774230214954390 1378417835.317938) (5774376239915166 1378417878.364230) (5774410701286164 1378417888.523001) (5774422667845704 1378417892.050590) (5774539112490184 1378417926.376981) (5774571702875116 1378417935.984210) (5774657736868886 1378417961.345930) (5774754030755392 1378417989.732136) (5774837526446812 1378418014.345597) (5774987344547920 1378418058.510055) (5775155787217148 1378418108.164798) (5775208631124714 1378418123.742505) (5775361628211774 1378418168.844088) (5775464127351960 1378418199.059523) (5775556158268630 1378418226.189061) (5775596535442956 1378418238.091735) (5775635307971582 1378418249.521381) (5775652458535950 1378418254.577149) (5775823485505474 1378418304.993711) (5775869978309974 1378418318.699195) (5776042068148968 1378418369.429076) (5776092103329310 1378418384.178806) (5776232457643112 1378418425.553461) (5776246053854976 1378418429.561450) (5776338724855086 1378418456.879676) (5776423685581914 1378418481.925011) (5776439318692018 1378418486.533452) (5776498649225386 1378418504.023334) (5776658728143968 1378418551.212552) (5776687965080272 1378418559.831227) (5776824984731414 1378418600.222868) (5776867502811518 1378418612.756655) (5776880287851594 1378418616.525521) (5777058462069672 1378418669.049004) (5777246583447208 1378418724.504783) (5777306700932132 1378418742.226648) (5777317800198880 1378418745.498570) (5777325772126384 1378418747.848593) (5777441817301192 1378418782.057227) (5777581170258410 1378418823.136698) (5777735914318004 1378418868.753269) (5777822732791466 1378418894.346247) (5777886691152052 1378418913.200354) (5777930214082596 1378418926.030358) (5777984622605818 1378418942.069296) (5778009919224262 1378418949.526416) (5778115323906818 1378418980.598370) (5778159943360406 1378418993.751615) (5778207407139432 1378419007.743331) (5778286187397330 1378419030.966744) (5778326629326754 1378419042.888508) (5778341214173942 1378419047.187935) (5778434010282150 1378419074.543041) (5778555326198696 1378419110.305424) (5778719457472992 1378419158.689230) (5778919490862270 1378419217.656522) (5778948400287868 1378419226.178652) (5778979018568318 1378419235.204530) (5779131079246534 1378419280.030078) (5779281609941378 1378419324.404604) (5779377737216680 1378419352.741696) (5779535658686930 1378419399.294923) (5779563918390830 1378419407.625522) (5779597304269366 1378419417.467252) (5779618292292234 1378419423.654252) (5779644953665016 1378419431.513684) (5779785106092284 1378419472.828826) (5779931006657106 1378419515.838443) (5780007861232752 1378419538.494186) (5780043665711702 1378419549.048887) (5780138519055964 1378419577.010436) (5780245119015328 1378419608.434737) (5780407560680144 1378419656.320454) (5780509482905382 1378419686.365817) (5780684533719342 1378419737.968551) (5780733064437068 1378419752.274785) (5780757670177772 1378419759.528242) (5780769060724798 1378419762.886029) (5780947510113102 1378419815.490625) (5781109842162880 1378419863.344038) (5781289525492930 1378419916.312392) (5781374153001068 1378419941.259501) (5781523236508206 1378419985.207420) (5781678525021040 1378420030.984496) (5781799176890606 1378420066.551130) (5781821080082971 1378420073.007912) (5781947139581796 1378420110.168648) (5782097649761718 1378420154.537130) (5782153497700840 1378420171.000391) (5782297350449036 1378420213.406347) (5782393699733178 1378420241.808889) (5782595852519298 1378420301.400951) (5782715768280560 1378420336.750588) (5782737418967686 1378420343.132934) (5782939326314266 1378420402.652645) (5783097188831466 1378420449.188501) (5783249762589404 1378420494.165298) (5783375016452206 1378420531.088536) (5783557432123866 1378420584.862344) (5783746512691544 1378420640.600875) (5783868849157282 1378420676.664096) (5783966089820018 1378420705.329397) (5784011296103100 1378420718.655629) (5784209918010446 1378420777.206821) (5784299315911040 1378420803.560175) (5784367790002884 1378420823.745458) (5784497675973734 1378420862.034174) (5784657052660712 1378420909.016376) (5784843080597568 1378420963.855022) (5784855354937372 1378420967.473340) (5784898910264774 1378420980.312891) (5785057674281008 1378421027.114486) (5785244527855870 1378421082.196530) (5785328240155424 1378421106.873844) (5785440184852638 1378421139.873707) (5785574772589334 1378421179.548450) (5785754758214370 1378421232.605914) (5785852104326244 1378421261.302308) (5785929523737032 1378421284.124563) (5786055569706216 1378421321.281310) (5786248863705388 1378421378.261920) (5786435189571884 1378421433.188413) (5786497295865820 1378421451.496557) (5786646358331974 1378421495.438273) (5786669530693488 1378421502.269190) (5786857383868348 1378421557.645910) (5787025272717092 1378421607.137401) (5787174517323074 1378421651.132805) (5787241889440000 1378421670.993245) (5787444400385332 1378421730.690885) (5787575957428770 1378421769.472220) (5787631057526918 1378421785.715025) (5787823792370268 1378421842.530791) (5787833072116010 1378421845.266341) (5787987720591542 1378421890.854733) (5788089558901720 1378421920.875363) (5788285960675960 1378421978.772093) (5788358133744916 1378422000.047790) (5788377760520664 1378422005.833512) (5788378976804756 1378422006.192057) (5788460124205766 1378422030.113273) (5788587496058704 1378422067.660866) (5788664320016688 1378422090.307585) (5788744620012628 1378422113.978994) (5788759463578472 1378422118.354687) (5788854632294758 1378422146.409206) (5788978005338258 1378422182.777999) (5789049627990166 1378422203.891440) (5789102035215682 1378422219.340419) (5789234059442018 1378422258.259470) (5789429570521870 1378422315.893633) (5789536883056618 1378422347.527995) (5789669473693988 1378422386.614017) (5789797568398586 1378422424.374698) (5789842628107100 1378422437.657724) (5789954769551560 1378422470.715588) (5790000149317696 1378422484.092963) (5790030059153404 1378422492.910000) (5790036566087472 1378422494.828161) (5790146232600074 1378422527.156447) (5790204835538582 1378422544.431844) (5790214042844212 1378422547.146040) (5790273537084756 1378422564.684181) (5790428276648730 1378422610.299426) (5790618944682960 1378422666.505924) (5790737823035550 1378422701.549742) (5790889475736998 1378422746.255018) (5790912001363356 1378422752.895284) (5791036518536564 1378422789.601354) (5791096865785820 1378422807.390950) (5791124084363334 1378422815.414639) (5791316423446608 1378422872.113742) (5791335552266074 1378422877.752674) (5791345835140982 1378422880.783934) (5791458843449212 1378422914.097340) (5791645376050082 1378422969.084768) (5791741892152834 1378422997.536482) (5791829593788534 1378423023.389803) (5791846880830380 1378423028.485802) (5791908189470112 1378423046.558806) (5791965338464642 1378423063.405599) (5792164453939072 1378423122.102298) (5792219905747900 1378423138.448783) (5792378625193133 1378423185.237249) (5792556899783504 1378423237.790323) (5792683715748198 1378423275.174050) (5792808103017530 1378423311.841830) (5792872366682100 1378423330.785939) (5792898355679162 1378423338.447164) (5792899106313948 1378423338.668441) (5793050318326786 1378423383.243811) (5793206599520670 1378423429.313510) (5793348490424556 1378423471.141133) (5793411558945352 1378423489.732926) (5793578602179450 1378423538.975134) (5793708524162710 1378423577.274469) (5793803889204804 1378423605.386861) (5793918947211918 1378423639.304485) (5794042543290038 1378423675.739024) (5794069125451882 1378423683.575104) (5794080850335604 1378423687.031449) (5794244302096858 1378423735.214934) (5794320522306948 1378423757.683674) (5794509262940314 1378423813.321992) (5794669983308924 1378423860.700299) (5794690416660602 1378423866.723789) (5794886666566584 1378423924.575747) (5795090034736270 1378423984.526084) (5795136513277762 1378423998.227364) (5795298627266150 1378424046.016498) (5795313590441564 1378424050.427451) (5795461615647048 1378424094.063395) (5795607652063758 1378424137.113070) (5795723971686652 1378424171.402614) (5795766424621864 1378424183.917199) (5795838021863028 1378424205.023154) (5795994520378998 1378424251.156923) (5795997260432657 1378424251.964656) (5796182254342616 1378424306.498504) (5796184869063596 1378424307.269290) (5796276363478142 1378424334.240677) (5796410264250618 1378424373.712916) (5796508150280156 1378424402.568470) (5796685318519654 1378424454.795408) (5796799818051182 1378424488.548411) (5796901445490140 1378424518.506884) (5796930534342110 1378424527.081906) (5796994502899142 1378424545.939020) (5797169794423608 1378424597.612722) (5797247906034938 1378424620.639027) (5797386010410436 1378424661.350430) (5797546228063750 1378424708.580544) (5797595344901934 1378424723.059558) (5797787738271342 1378424779.774657) (5797943275426464 1378424825.625013) (5798037852045636 1378424853.504987) (5798180000144580 1378424895.408426) (5798358713513730 1378424948.090835) (5798370033906762 1378424951.427942) (5798378442605560 1378424953.906719) (5798490324913800 1378424986.888187) (5798673194945684 1378425040.795927) (5798735110396030 1378425059.047807) (5798930618086634 1378425116.680968) (5798967516164898 1378425127.558049) (5799110083672558 1378425169.585124) (5799308368755920 1378425228.037029) (5799317587804954 1378425230.754687) (5799424261743584 1378425262.200802) (5799558187281992 1378425301.680341) (5799690385604946 1378425340.650722) (5799766664219556 1378425363.136685) (5799932776437578 1378425412.104452) (5799980621500204 1378425426.208567) (5800073347936164 1378425453.543140) (5800084570735460 1378425456.851478) (5800175212220616 1378425483.571434) (5800365425907536 1378425539.644008) (5800557842215154 1378425596.365882) (5800596205116014 1378425607.674776) (5800700228913620 1378425638.339664) (5800793959710558 1378425665.970306) (5800959236777374 1378425714.691874) (5801034283020174 1378425736.814548) (5801045980743922 1378425740.262887) (5801208715181880 1378425788.234918) (5801398579087984 1378425844.204367) (5801508688094318 1378425876.663093) (5801599900272150 1378425903.551274) (5801711849951128 1378425936.552605) (5801716255156632 1378425937.851204) (5801724537797404 1378425940.292820) (5801862833291754 1378425981.060558) (5801978876779790 1378426015.268691) (5802090382125288 1378426048.139037) (5802113470283142 1378426054.945130) (5802164114046084 1378426069.874263) (5802364284696676 1378426128.882007) (5802536287472092 1378426179.586221) (5802634682543832 1378426208.591828) (5802820587728354 1378426263.394295) (5803004514431404 1378426317.613533) (5803161577671052 1378426363.913764) (5803319636460724 1378426410.507475) (5803404258549024 1378426435.452985) (5803555382237774 1378426480.002316) (5803710695787690 1378426525.786764) (5803720712375506 1378426528.739525) (5803777843203826 1378426545.580963) (5803911746087556 1378426585.053821) (5804063122452406 1378426629.677640) (5804115567830172 1378426645.137867) (5804248788503666 1378426684.409622) (5804282708145100 1378426694.408699) (5804315182485012 1378426703.981720) (5804363912425798 1378426718.346685) (5804398132472684 1378426728.434319) (5804428290080256 1378426737.324397) (5804552780693540 1378426774.022643) (5804658636068128 1378426805.227458) (5804682969546896 1378426812.400658) (5804863316510486 1378426865.564644) (5804957542666030 1378426893.341314) (5805003485083706 1378426906.884553) (5805033842409284 1378426915.833506) (5805200969372726 1378426965.100404) (5805246890838192 1378426978.637466) (5805283504348390 1378426989.430662) (5805449914323734 1378427038.486199) (5805483760237816 1378427048.463542) (5805610058283586 1378427085.694593) (5805661954732772 1378427100.993003) (5805852920029410 1378427157.287130) (5806007621398676 1378427202.891113) (5806017070356066 1378427205.676545) (5806075232585938 1378427222.822025) (5806145099612248 1378427243.417930) (5806281513929226 1378427283.631123) (5806412751790660 1378427322.318366) (5806582921853016 1378427372.482321) (5806669248050370 1378427397.930178) ) core-113.00.00/src/time_stamp_counter_stubs.c000066400000000000000000000017011256461075500210320ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __MACH__ #include #include #endif #include "ocaml_utils.h" CAMLprim value tsc_get() { #ifdef __x86_64__ uint32_t hi, lo; __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); /* Given we're on x86_64, caml_alloc_int63 should expand to Val_long, and hence * the stub may be marked noalloc */ return caml_alloc_int63( ((uint64_t)lo) | (((uint64_t)hi)<<32) ); #else #define NANOS_PER_SECOND 1000000000 struct timespec ts; if ( clock_gettime( CLOCK_MONOTONIC, &ts ) != 0 ) unix_error(errno, "clock_gettime", Nothing); else return caml_alloc_int63(NANOS_PER_SECOND * ts.tv_sec + ts.tv_nsec); #endif } core-113.00.00/src/timespec.c000066400000000000000000000005131256461075500155220ustar00rootroot00000000000000#include #include struct timespec timespec_of_double(double seconds) { struct timespec ts; ts.tv_sec = (time_t) floor(seconds); ts.tv_nsec = (long) (1e9 * (seconds - ts.tv_sec)); return ts; } double timespec_to_double(struct timespec ts) { return (double) ts.tv_sec + ((double) ts.tv_nsec / 1e9); } core-113.00.00/src/timespec.h000066400000000000000000000001661256461075500155330ustar00rootroot00000000000000#include struct timespec timespec_of_double(double seconds); double timespec_to_double(struct timespec ts); core-113.00.00/src/timing_wheel_float.ml000066400000000000000000000107451256461075500177470ustar00rootroot00000000000000(* A key idea behind this implementation is that it only deals with [Time_ns] and [Time_ns.Span] values that are multiples of a microsecond. This follows from the fact that every [Time] or [Time.Span] is converted to [Time_ns] or [Time_ns.Span] using [Time_ns.of_time] or [Time_ns.Span.of_span] before doing anything with it. Because [Time_ns.Span.of_span] and [Time_ns.of_time] round to the nearest microsecond, all [Time_ns] and [Time_ns.Span] values in this implementation will be a multiple of one microsecond. Because of this, they satisfy: - [Time_ns.of_time (Time_ns.to_time time_ns) = time_ns] - [Time_ns.Span.of_span (Time_ns.Span.to_span time_ns_span) = time_ns_span] *) module Time_ns_in_this_directory = Time_ns open Core_kernel.Std module Time_ns = Time_ns_in_this_directory module Time = Time (* for the .mli *) module Interval_num = Timing_wheel_ns.Interval_num module Level_bits = Timing_wheel_ns.Level_bits module Priority_queue = Timing_wheel_ns.Priority_queue let to_span = Time_ns.Span.to_span let to_time = Time_ns.to_time type 'a t = 'a Timing_wheel_ns.t with sexp_of type 'a t_now = 'a t with sexp_of type 'a timing_wheel = 'a t module Alarm = struct include Timing_wheel_ns.Alarm let at timing_wheel t = to_time (at timing_wheel t) end let nanoseconds_per_microsecond = 1000 let invariant_span span = <:test_result< int >> ~expect:0 (Int.rem (Time_ns.Span.to_int_ns span) nanoseconds_per_microsecond) ;; let invariant_time time = <:test_result< int >> ~expect:0 (Int.rem (Time_ns.to_int_ns_since_epoch time) nanoseconds_per_microsecond) ;; let invariant invariant_a t = invariant_span (Timing_wheel_ns.alarm_precision t); invariant_time (Timing_wheel_ns.now t); invariant_time (Timing_wheel_ns.start t); Timing_wheel_ns.invariant invariant_a t; Timing_wheel_ns.iter t ~f:(fun alarm -> invariant_time (Timing_wheel_ns.Alarm.at t alarm)); ;; module Config = struct include Timing_wheel_ns.Config let create ?alarm_precision ?level_bits () = create () ?alarm_precision:(Option.map alarm_precision ~f:Time_ns.Span.of_span) ?level_bits ;; let alarm_precision t = to_span (alarm_precision t) let durations t = List.map (durations t) ~f:to_span end let add t ~at a = Timing_wheel_ns.add t ~at:(Time_ns.of_time at) a let add_at_interval_num = Timing_wheel_ns.add_at_interval_num let advance_clock t ~to_ ~handle_fired = Timing_wheel_ns.advance_clock t ~to_:(Time_ns.of_time to_) ~handle_fired; ;; let fire_past_alarms t ~handle_fired = Timing_wheel_ns.fire_past_alarms t ~handle_fired; ;; let alarm_precision t = to_span (Timing_wheel_ns.alarm_precision t) let alarm_upper_bound t = to_time (Timing_wheel_ns.alarm_upper_bound t) let clear = Timing_wheel_ns.clear let create ~config ~start = Timing_wheel_ns.create ~config ~start:(Time_ns.of_time start) let interval_num t time = Timing_wheel_ns.interval_num t (Time_ns.of_time time) let interval_num_start t n = to_time (Timing_wheel_ns.interval_num_start t n) let interval_start t time = to_time (Timing_wheel_ns.interval_start t (Time_ns.of_time time)) ;; let is_empty = Timing_wheel_ns.is_empty let iter = Timing_wheel_ns.iter let length = Timing_wheel_ns.length let mem = Timing_wheel_ns.mem let next_alarm_fires_at t = match Timing_wheel_ns.next_alarm_fires_at t with | None -> None | Some time -> Some (to_time time) ;; let now t = to_time (Timing_wheel_ns.now t) let now_interval_num = Timing_wheel_ns.now_interval_num let remove = Timing_wheel_ns.remove let reschedule t alarm ~at = Timing_wheel_ns.reschedule t alarm ~at:(Time_ns.of_time at) let reschedule_at_interval_num = Timing_wheel_ns.reschedule_at_interval_num let start t = to_time (Timing_wheel_ns.start t) (* Here is a proof that [interval_num] is the inverse of [interval_num_start], i.e.: {[ interval_num t (interval_num_start t n) = n ]} Expanding the definitions, we have that: {[ interval_num t (interval_num_start t n) = Timing_wheel.interval_num t (Time_ns.of_time (to_time (Timing_wheel.interval_num_start t n))) ]} Because [start t] and [alarm_precision t] are multiples of one microsecond, [Timing_wheel.interval_num_start] returns a time that is a multiple of one microsecond; hence [Time_ns.of_time] is the inverse of [to_time]. Hence, the above is equal to: {[ Timing_wheel.interval_num t (Timing_wheel.interval_num_start t n) ]} But this is [n], by the analogous inverse property on [Timing_wheel_ns]. *) core-113.00.00/src/timing_wheel_float.mli000066400000000000000000000017731256461075500201210ustar00rootroot00000000000000(** A timing wheel in which time is represented by [Time.t], i.e. a floating-point number of seconds since the epoch. The implementation uses [Timing_wheel_ns], and rounds all [Time.t] values to the nearest microsecond before feeding them to the underlying timing wheel. Thus, it is possible that [Time.( < ) (Alarm.at t (add t ~at a)) at], with the alarm's [at] being up to a microsecond earlier than requested. However, because the alarm precision of the underlying timing wheel is an integer number of microseconds, we are still guaranteed when an alarm fires that [at < now t], i.e. the timing-wheel's clock is beyond the time requested for the alarm to fire. Due to floating-point arithmetic, the guarantee that alarms don't fire too late needs to be weakened slightly to use [ >= ] rather than [ > ]. For all alarms [a] in [t]: {[ Alarm.at a >= now t - alarm_precision t ]} *) include Core_kernel.Timing_wheel_intf.Timing_wheel with module Time = Time core-113.00.00/src/timing_wheel_float_unit_tests.ml000066400000000000000000000023351256461075500222240ustar00rootroot00000000000000open Core_kernel.Std (* module Timing_wheel_float = Timing_wheel_debug.Debug (Time) (Timing_wheel_float) *) open Timing_wheel_float include Core_kernel.Timing_wheel_unit_tests.Make (Timing_wheel_float) let sec = Time.Span.of_sec TEST_UNIT = let t = create_unit () in let start = start t in List.iter [ Time.sub start (sec (2. *. Float.of_int Int.max_value)) ; Time.add start (sec (2. *. Float.of_int Int.max_value)) ; Time.of_float Float.max_value ] ~f:(fun time -> assert (does_raise (fun () -> interval_num t time)); assert (does_raise (fun () -> interval_start t time))); ;; (* Check that default [level_bits] gives desired range of times. *) TEST_UNIT = let zone = Time.Zone.find_exn "America/New_York" in let start = Time.of_date_ofday ~zone (Date.create_exn ~y:2000 ~m:Month.Jan ~d:1) Time.Ofday.start_of_day in let alarm_precision = Time.Span.microsecond in let max_alarm_lower_bound = Date.create_exn ~y:2073 ~m:Month.Jan ~d:1 in let level_bits = Level_bits.default in let t = create ~config:(Config.create ~level_bits ~alarm_precision ()) ~start in assert (Date.(>=) (Time.to_date ~zone (alarm_upper_bound t)) max_alarm_lower_bound) ;; core-113.00.00/src/timing_wheel_float_unit_tests.mli000066400000000000000000000000331256461075500223660ustar00rootroot00000000000000(** Deliberately empty. *) core-113.00.00/src/tuple.ml000066400000000000000000000000321256461075500152240ustar00rootroot00000000000000include Core_kernel.Tuple core-113.00.00/src/type_equal.ml000066400000000000000000000000371256461075500162500ustar00rootroot00000000000000include Core_kernel.Type_equal core-113.00.00/src/union_find.ml000066400000000000000000000000371256461075500162300ustar00rootroot00000000000000include Core_kernel.Union_find core-113.00.00/src/unique_id.ml000066400000000000000000000000361256461075500160610ustar00rootroot00000000000000include Core_kernel.Unique_id core-113.00.00/src/unique_id_intf.ml000066400000000000000000000000431256461075500170770ustar00rootroot00000000000000include Core_kernel.Unique_id_intf core-113.00.00/src/unit.ml000066400000000000000000000000311256461075500150510ustar00rootroot00000000000000include Core_kernel.Unit core-113.00.00/src/univ.ml000066400000000000000000000000311256461075500150530ustar00rootroot00000000000000include Core_kernel.Univ core-113.00.00/src/univ_map.ml000066400000000000000000000000351256461075500157140ustar00rootroot00000000000000include Core_kernel.Univ_map core-113.00.00/src/unix_error.ml000066400000000000000000000021761256461075500163020ustar00rootroot00000000000000open Core_kernel.Std (** @deprecated in favor of [t], below. *) type error = Unix.error = E2BIG | EACCES | EAGAIN | EBADF | EBUSY | ECHILD | EDEADLK | EDOM | EEXIST | EFAULT | EFBIG | EINTR | EINVAL | EIO | EISDIR | EMFILE | EMLINK | ENAMETOOLONG | ENFILE | ENODEV | ENOENT | ENOEXEC | ENOLCK | ENOMEM | ENOSPC | ENOSYS | ENOTDIR | ENOTEMPTY | ENOTTY | ENXIO | EPERM | EPIPE | ERANGE | EROFS | ESPIPE | ESRCH | EXDEV | EWOULDBLOCK | EINPROGRESS | EALREADY | ENOTSOCK | EDESTADDRREQ | EMSGSIZE | EPROTOTYPE | ENOPROTOOPT | EPROTONOSUPPORT | ESOCKTNOSUPPORT | EOPNOTSUPP | EPFNOSUPPORT | EAFNOSUPPORT | EADDRINUSE | EADDRNOTAVAIL | ENETDOWN | ENETUNREACH | ENETRESET | ECONNABORTED | ECONNRESET | ENOBUFS | EISCONN | ENOTCONN | ESHUTDOWN | ETOOMANYREFS | ETIMEDOUT | ECONNREFUSED | EHOSTDOWN | EHOSTUNREACH | ELOOP | EOVERFLOW | EUNKNOWNERR of int with sexp, compare type t = error with sexp, compare external of_errno : int -> t = "core_unix_error_of_code" external to_errno : t -> int = "core_code_of_unix_error" TEST_UNIT = for i = 1 to 10000 do <:test_result< int >> ~expect:i (to_errno (of_errno i)) done; ;; core-113.00.00/src/unix_stubs.c000066400000000000000000001456421256461075500161310ustar00rootroot00000000000000/* Core_unix support functions written in C. */ #define _GNU_SOURCE #include #include /* Darwin needs this to be included before if.h*/ #if defined(__APPLE__) #define _POSIX_SOURCE #include #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #define stat64 stat #define lstat64 lstat #define fstat64 fstat #endif #include #include #include "timespec.h" #if defined(JSC_WORDEXP) #include #endif CAMLprim value core_unix_error_of_code(value code) { return unix_error_of_code(Int_val(code)); } CAMLprim value core_code_of_unix_error(value error) { return Val_int(code_of_unix_error(error)); } CAMLprim value unix_error_stub(value v_errcode, value v_cmdname, value cmd_arg) { unix_error(Int_val(v_errcode), String_val(v_cmdname), cmd_arg); return Val_unit; } #define MAX_ERROR_LEN 4096 extern char **environ; static void report_error(int fd, const char* str) { char buf[MAX_ERROR_LEN]; char buf2[MAX_ERROR_LEN]; #ifdef __GLIBC__ snprintf(buf2, MAX_ERROR_LEN, "%s (%s)\n", str, strerror_r(errno, buf, MAX_ERROR_LEN)); #else if (strerror_r(errno, buf, MAX_ERROR_LEN) == -1) snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", errno); snprintf(buf2, MAX_ERROR_LEN, "%s (%s)\n", str, buf); #endif buf2[MAX_ERROR_LEN - 1] = '\0'; if (write(fd, buf2, strlen(buf2))) {} /* The returned value from the above write is ignored. This is fine because we are about to exit(254). But newer versions of gcc warn, so we enclose the expression with `if(..){}'. Note: simply casting to (void) is not sufficient to suppress the warning. */ } /* Maximum number of arguments plus one (for terminating NULL) that may be passed to execv/execvp. 4096 is the minimum that POSIX allows, but note that it is not specified how much argument space is used up by variables in the user's environment. This makes it hard to predict whether the system call can fail due to too many (implicit) arguments. */ /* Note: the ARG_MAX defined in sys/limits.h can be huge */ #define ML_ARG_MAX (4096 + 1) #define UNIX_INT63_CONST(CONST) DEFINE_INT63_CONSTANT(unix_##CONST,CONST) UNIX_INT63_CONST(F_GETFL) UNIX_INT63_CONST(F_SETFL) UNIX_INT63_CONST(O_APPEND) UNIX_INT63_CONST(O_ASYNC) #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif UNIX_INT63_CONST(O_CLOEXEC) UNIX_INT63_CONST(O_CREAT) #ifndef O_DIRECT #define O_DIRECT 0 #endif UNIX_INT63_CONST(O_DIRECT) #ifndef O_DIRECTORY #define O_DIRECTORY 0 #endif UNIX_INT63_CONST(O_DIRECTORY) #ifndef O_DSYNC #define O_DSYNC 0 #endif UNIX_INT63_CONST(O_DSYNC) UNIX_INT63_CONST(O_EXCL) #ifndef O_NOATIME #define O_NOATIME 0 #endif UNIX_INT63_CONST(O_NOATIME) UNIX_INT63_CONST(O_NOCTTY) UNIX_INT63_CONST(O_NOFOLLOW) UNIX_INT63_CONST(O_NONBLOCK) UNIX_INT63_CONST(O_RDONLY) UNIX_INT63_CONST(O_RDWR) #ifndef O_RSYNC #define O_RSYNC 0 #endif UNIX_INT63_CONST(O_RSYNC) UNIX_INT63_CONST(O_SYNC) UNIX_INT63_CONST(O_TRUNC) UNIX_INT63_CONST(O_WRONLY) CAMLprim value unix_fcntl (value fd, value v_cmd, value v_arg) { int63 result; int cmd = Int63_val(v_cmd); /* extract before blocking section */ long arg = Int63_val(v_arg); /* extract before blocking section */ caml_enter_blocking_section(); result = fcntl(Int_val(fd), cmd, arg); caml_leave_blocking_section(); if (result == -1) uerror("unix_fcntl", Nothing); return caml_alloc_int63(result); } int core_unix_close_durably(int fd) { int ret; do ret = close(fd); while (ret == -1 && errno == EINTR); return ret; } void close_on_exec(int fd) { int flags; flags = fcntl(fd, F_GETFD); if (flags == -1) { unix_error(errno, "close_on_exec: unable to get flags for descr", Nothing); }; flags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags) == -1) { unix_error(errno, "close_on_exec: unable to set flags for descr", Nothing); }; } /* Close function that handles signals correctly by retrying the close after EINTR. NOTE: we should never see EIO when closing pipes. If so, it is reasonable to see this as a kernel bug, and it's pretty useless trying to catch/work around potential kernel bugs. We assume that it works. An EBADF would be bad when closing successfully opened pipes, too, but in that case the pipe should be guaranteed to be closed anyway (unlike EIO). This covers all errors that close could potentially return. */ static inline int safe_close(int fd) { int ret; while ((ret = close(fd)) == -1 && errno == EINTR) /* empty loop */ ; return ret; } /* Idempotent version of safe_close: doesn't flag EBADF as an error. */ static inline int safe_close_idem(int fd) { int ret = safe_close(fd); return (ret == -1 && errno == EBADF) ? 0 : ret; } /* This function is defined in stubs for the Unix module of the standard OCaml distribution. It allocates a NULL-terminated array of strings and fill it will strings contained in the string array [arg]. Pointers stored in the result points directly inside the OCaml heap. */ extern char **cstringvect(value arg); /* Given v_prog, an O'Caml string value specifying a program name, v_args, an O'Caml array specifying program arguments (not including the program name), and v_search_path, an O'Caml boolean value specifying whether to search the PATH, fork a child process that executes the specified program. Return the child's pid together with fds connected via pipes to the stdin, stdout and stderr of the program such that if the fds are closed the pipes are broken. Beware! A great deal of work has gone into making this subtle function thoroughly robust and, hopefully, correct. Changes should not be undertaken lightly. */ CAMLprim value ml_create_process(value v_working_dir, value v_prog, value v_args, value v_env, value v_search_path) { /* No need to protect the arguments or other values: we never release the O'Caml lock, and we never use O'Caml values after other values get allocated in the O'Caml heap. */ typedef enum { READ_END = 0, WRITE_END = 1 } pipe_end_t; value v_res; int stdin_pfds[2]; int stdout_pfds[2]; int stderr_pfds[2]; int child_pid; int my_errno; /* It's ok to hold pointers into the O'Caml heap, since the memory space gets duplicated upon the fork, during which we keep the O'Caml lock. */ char *prog = String_val(v_prog); int search_path = Bool_val(v_search_path); /* We use a statically allocated, fixed-size array for performance reasons. It is reasonable to assume that the array can never become too big for stack allocations anyway. */ char *args[ML_ARG_MAX]; int n_args = Wosize_val(v_args); char *working_dir = NULL; /* Note that the executable name also counts as an argument, and we also have to subtract one more for the terminating NULL! */ if (n_args >= ML_ARG_MAX - 1) caml_failwith("too many arguments for Unix.create_process"); args[0] = prog; args[n_args + 1] = NULL; while (n_args) { args[n_args] = String_val(Field(v_args, n_args - 1)); --n_args; } if (pipe(stdin_pfds) == -1) uerror("create_process: parent->stdin pipe creation failed", Nothing); if (pipe(stdout_pfds) == -1) { my_errno = errno; safe_close(stdin_pfds[READ_END]); safe_close(stdin_pfds[WRITE_END]); unix_error(my_errno, "create_process: stdout->parent pipe creation failed", Nothing); } if (pipe(stderr_pfds) == -1) { my_errno = errno; safe_close(stdin_pfds[READ_END]); safe_close(stdin_pfds[WRITE_END]); safe_close(stdout_pfds[READ_END]); safe_close(stdout_pfds[WRITE_END]); unix_error(my_errno, "create_process: stderr->parent pipe creation failed", Nothing); } /* This function deliberately doesn't release the O'Caml lock (i.e. it doesn't call caml_enter_blocking_section) during the fork. This is because we hold pointers into the ML heap across a fork, and releasing the lock immediately before the fork could theoretically cause the GC to run and move blocks before the fork duplicates the memory space. If the parent process has threads that turn out to suffer from too much latency during this fork, we may want to rewrite this function to copy the O'Caml values into the C heap before the fork and release the O'Caml lock. It seems unlikely that forks will ever take so long that people care. In Linux 2.6 forks are practically constant time even in the presence of ridiculous amounts of processes, and are reported to always have less than 500us latency. Maybe the kernel does not even schedule threads during forks anyway. */ if ((child_pid = fork()) == 0) { /* Child process. */ /* Just in case any of the pipes' file descriptors are 0, 1 or 2 (not inconceivable, especially when running as a daemon), duplicate all three descriptors we need in the child to fresh descriptors before duplicating them onto stdin, stdout and stderr. It is in fact the case that none of [temp_stdin], [temp_stdout] and [temp_stderr] will never be 0, 1, or 2. That this is so follows from the following three properties: 1. The kernel always allocates the lowest-numbered unused fd when asked for a new one. 2. We allocated more than two fds during the calls to [pipe] above. 3. We have not closed any fds between the calls to [pipe] above and this point. */ int temp_stdin = dup(stdin_pfds[READ_END]); int temp_stdout = dup(stdout_pfds[WRITE_END]); int temp_stderr = dup(stderr_pfds[WRITE_END]); if (temp_stdin == -1 || temp_stdout == -1 || temp_stderr == -1) { /* Errors here and below are sent back to the parent on the stderr pipe. */ report_error(stderr_pfds[WRITE_END], "could not dup fds in child process"); /* The open fds will be cleaned up by exit(); likewise below. We use 254 to avoid any clash with ssh returning 255. */ exit(254); } /* We are going to replace stdin, stdout, and stderr for this child process so we close the existing descriptors now. They may be closed already so we ignore EBADF from close. */ /* We don't have to do this ([dup2] closes the newfd if it is open before splatting the oldfd on it), but maybe we get a more informative error message if there is a problem closing a descriptor rather than with the dup operation itself. */ if (safe_close_idem(STDIN_FILENO) == -1 || safe_close_idem(STDOUT_FILENO) == -1 || safe_close_idem(STDERR_FILENO) == -1) { report_error(temp_stderr, "could not close standard descriptors in child process"); exit(254); } /* All pipe fds propagated from parent to child via fork() must be closed, otherwise the reference counts on those fds won't drop to zero (and cause the pipe to be broken) when the parent closes them. */ safe_close(stdin_pfds[READ_END]); safe_close(stdin_pfds[WRITE_END]); safe_close(stdout_pfds[READ_END]); safe_close(stdout_pfds[WRITE_END]); safe_close(stderr_pfds[READ_END]); safe_close(stderr_pfds[WRITE_END]); /* We must dup2 after closing the pfds, because the latter might have been standard descriptors. */ if (dup2(temp_stdin, STDIN_FILENO) == -1 || dup2(temp_stdout, STDOUT_FILENO) == -1 || dup2(temp_stderr, STDERR_FILENO) == -1) { report_error(temp_stderr, "could not dup2 fds in child process"); exit(254); } safe_close(temp_stdin); safe_close(temp_stdout); safe_close(temp_stderr); /* We don't bother saving/restoring the environment or freeing the new one since we exit the process in case of error. */ environ = cstringvect(v_env); if (Is_block(v_working_dir)) working_dir = String_val(Field(v_working_dir, 0)); if (working_dir && chdir(working_dir) == -1) { report_error(STDERR_FILENO, "chdir failed in child process"); exit(254); } if ((search_path ? execvp : execv)(prog, args) == -1) { report_error(STDERR_FILENO, "execvp/execv failed in child process"); exit(254); } } my_errno = errno; /* Parent process. */ /* Close the ends of the pipes that we [the parent] aren't going to use. */ safe_close(stdin_pfds[READ_END]); safe_close(stdout_pfds[WRITE_END]); safe_close(stderr_pfds[WRITE_END]); /* Set the ends we are going to use to close on exec, so the next child we * fork doesn't get an unwanted inheritance. */ close_on_exec(stdin_pfds[WRITE_END]); close_on_exec(stdout_pfds[READ_END]); close_on_exec(stderr_pfds[READ_END]); /* If the fork failed, cause the pipes to be destroyed and fail. */ if (child_pid == -1) { safe_close(stdin_pfds[WRITE_END]); safe_close(stdout_pfds[READ_END]); safe_close(stderr_pfds[READ_END]); unix_error(my_errno, "create_process: failed to fork", Nothing); } /* Must use Field as an lvalue after caml_alloc_small -- not Store_field. */ v_res = caml_alloc_small(4, 0); Field(v_res, 0) = Val_int(child_pid); Field(v_res, 1) = Val_int(stdin_pfds[WRITE_END]); Field(v_res, 2) = Val_int(stdout_pfds[READ_END]); Field(v_res, 3) = Val_int(stderr_pfds[READ_END]); return v_res; } /* Replacement for broken stat functions */ static int file_kind_table[] = { S_IFREG, S_IFDIR, S_IFCHR, S_IFBLK, S_IFLNK, S_IFIFO, S_IFSOCK }; #define Val_file_offset(fofs) caml_copy_int64(fofs) static value cst_to_constr(int n, int *tbl, int size, int deflt) { int i; for (i = 0; i < size; i++) if (n == tbl[i]) return Val_int(i); return Val_int(deflt); } static value core_stat_aux_64(struct stat64 *buf) { CAMLparam0(); CAMLlocal5(atime, mtime, ctime, offset, v); #include "nanosecond_stat.h" atime = caml_copy_double((double) buf->st_atime + (buf->NSEC(a) / 1000000000.0)); mtime = caml_copy_double((double) buf->st_mtime + (buf->NSEC(m) / 1000000000.0)); ctime = caml_copy_double((double) buf->st_ctime + (buf->NSEC(c) / 1000000000.0)); #undef NSEC offset = Val_file_offset(buf->st_size); v = caml_alloc_small(12, 0); Field (v, 0) = Val_int (buf->st_dev); Field (v, 1) = Val_int (buf->st_ino); Field (v, 2) = cst_to_constr(buf->st_mode & S_IFMT, file_kind_table, sizeof(file_kind_table) / sizeof(int), 0); Field (v, 3) = Val_int (buf->st_mode & 07777); Field (v, 4) = Val_int (buf->st_nlink); Field (v, 5) = Val_int (buf->st_uid); Field (v, 6) = Val_int (buf->st_gid); Field (v, 7) = Val_int (buf->st_rdev); Field (v, 8) = offset; Field (v, 9) = atime; Field (v, 10) = mtime; Field (v, 11) = ctime; CAMLreturn(v); } static inline char * core_copy_to_c_string(value v_str) { asize_t len = caml_string_length(v_str) + 1; char *p = caml_stat_alloc(len); memcpy(p, String_val(v_str), len); return p; } CAMLprim value core_unix_stat_64(value path) { CAMLparam1(path); int ret; struct stat64 buf; char *p = core_copy_to_c_string(path); caml_enter_blocking_section(); ret = stat64(p, &buf); caml_stat_free(p); caml_leave_blocking_section(); if (ret == -1) uerror("stat", path); CAMLreturn(core_stat_aux_64(&buf)); } CAMLprim value core_unix_lstat_64(value path) { CAMLparam1(path); int ret; struct stat64 buf; char *p = core_copy_to_c_string(path); caml_enter_blocking_section(); ret = lstat64(p, &buf); caml_stat_free(p); caml_leave_blocking_section(); if (ret == -1) uerror("lstat", path); CAMLreturn(core_stat_aux_64(&buf)); } CAMLprim value core_unix_fstat_64(value fd) { int ret; struct stat64 buf; caml_enter_blocking_section(); ret = fstat64(Int_val(fd), &buf); caml_leave_blocking_section(); if (ret == -1) uerror("fstat", Nothing); return core_stat_aux_64(&buf); } CAMLprim value core_setpwent(value v_unit) { CAMLparam1(v_unit); caml_enter_blocking_section(); setpwent(); caml_leave_blocking_section(); CAMLreturn(Val_unit); } CAMLprim value core_endpwent(value v_unit) { CAMLparam1(v_unit); caml_enter_blocking_section(); endpwent(); caml_leave_blocking_section(); CAMLreturn(Val_unit); } CAMLprim value core_getpwent(value v_unit) { CAMLparam1(v_unit); CAMLlocal1(res); struct passwd *entry; caml_enter_blocking_section(); errno = 0; entry = getpwent(); caml_leave_blocking_section(); if (entry == NULL) { if (errno == 0) caml_raise_end_of_file(); else unix_error(errno, "getpwent", Nothing); } res = caml_alloc_tuple(7); Store_field(res, 0, caml_copy_string(entry->pw_name)); Store_field(res, 1, caml_copy_string(entry->pw_passwd)); Store_field(res, 2, Val_int(entry->pw_uid)); Store_field(res, 3, Val_int(entry->pw_gid)); Store_field(res, 4, caml_copy_string(entry->pw_gecos)); Store_field(res, 5, caml_copy_string(entry->pw_dir)); Store_field(res, 6, caml_copy_string(entry->pw_shell)); CAMLreturn(res); } #define FLOCK_BUF_LENGTH 80 CAMLprim value core_unix_flock(value v_fd, value v_lock_type) { CAMLparam2(v_fd, v_lock_type); int fd = Int_val(v_fd); int lock_type = Int_val(v_lock_type); int operation; int res; char error[FLOCK_BUF_LENGTH]; /* The [lock_type] values are defined in core_unix.ml. */ switch(lock_type) { case 0: operation = LOCK_SH; break; case 1: operation = LOCK_EX; break; case 2: operation = LOCK_UN; break; default: snprintf(error, FLOCK_BUF_LENGTH, "bug in flock C stub: unknown lock type: %d", lock_type); caml_invalid_argument(error); }; /* always try a non-blocking lock */ operation = operation | LOCK_NB; caml_enter_blocking_section(); res = flock(fd, operation); caml_leave_blocking_section(); if (res) { switch(errno) { case EWOULDBLOCK: CAMLreturn(Val_false); default: unix_error(errno, "core_unix_flock", Nothing); }; }; CAMLreturn(Val_true); } /* Filesystem functions */ CAMLprim value unix_mknod_stub( value v_pathname, value v_mode, value v_perm, value v_major, value v_minor) { CAMLparam1(v_pathname); int ret, len; char *pathname; mode_t mode = Int_val(v_perm); dev_t dev = 0; switch (Int_val(v_mode)) { case 0 : mode |= S_IFREG; break; case 2 : mode |= S_IFCHR; dev = makedev(Int_val(v_major), Int_val(v_minor)); break; case 3 : mode |= S_IFBLK; dev = makedev(Int_val(v_major), Int_val(v_minor)); break; case 5 : mode |= S_IFIFO; break; case 6 : mode |= S_IFSOCK; break; default : caml_invalid_argument("mknod"); } len = caml_string_length(v_pathname) + 1; pathname = caml_stat_alloc(len); memcpy(pathname, String_val(v_pathname), len); caml_enter_blocking_section(); ret = mknod(pathname, mode, dev); caml_stat_free(pathname); caml_leave_blocking_section(); if (ret == -1) uerror("mknod", v_pathname); CAMLreturn(Val_unit); } /* I/O functions */ typedef struct dirent directory_entry; CAMLprim value unix_sync(value v_unit) { caml_enter_blocking_section(); sync(); caml_leave_blocking_section(); return v_unit; } CAMLprim value unix_fsync(value v_fd) { int ret; caml_enter_blocking_section(); ret = fsync(Int_val(v_fd)); caml_leave_blocking_section(); if (ret == -1) uerror("fsync", Nothing); return Val_unit; } #if defined(_POSIX_SYNCHRONIZED_IO) && (_POSIX_SYNCHRONIZED_IO > 0) CAMLprim value unix_fdatasync(value v_fd) { int ret; caml_enter_blocking_section(); ret = fdatasync(Int_val(v_fd)); caml_leave_blocking_section(); if (ret == -1) uerror("fdatasync", Nothing); return Val_unit; } #else #warning "_POSIX_SYNCHRONIZED_IO undefined or <= 0; aliasing unix_fdatasync to unix_fsync" CAMLprim value unix_fdatasync(value v_fd) { return unix_fsync(v_fd); } #endif CAMLprim value unix_dirfd(value v_dh) { int ret = 0; if (DIR_Val(v_dh) == NULL) caml_invalid_argument("dirfd: NULL directory handle (probably closed)"); ret = dirfd(DIR_Val(v_dh)); if (ret == -1) uerror("dirfd", Nothing); return Val_int(ret); } CAMLprim value unix_readdir_ino_stub(value v_dh) { DIR *d; directory_entry * e; d = DIR_Val(v_dh); if (d == (DIR *) NULL) unix_error(EBADF, "readdir_ino", Nothing); caml_enter_blocking_section(); e = readdir((DIR *) d); caml_leave_blocking_section(); if (e == (directory_entry *) NULL) caml_raise_end_of_file(); else { CAMLparam0(); CAMLlocal2(v_name, v_ino); value v_res; v_name = caml_copy_string(e->d_name); v_ino = caml_copy_nativeint(e->d_ino); v_res = caml_alloc_small(2, 0); Field(v_res, 0) = v_name; Field(v_res, 1) = v_ino; CAMLreturn(v_res); } } CAMLprim value unix_read_assume_fd_is_nonblocking_stub( value v_fd, value v_buf, value v_pos, value v_len) { char *buf = String_val(v_buf) + Long_val(v_pos); ssize_t ret = read(Int_val(v_fd), buf, Long_val(v_len)); if (ret == -1) uerror("unix_read_assume_fd_is_nonblocking", Nothing); return Val_long(ret); } CAMLprim value unix_write_assume_fd_is_nonblocking_stub( value v_fd, value v_buf, value v_pos, value v_len) { char *buf = String_val(v_buf) + Long_val(v_pos); ssize_t ret = write(Int_val(v_fd), buf, Long_val(v_len)); if (ret == -1) uerror("unix_write_assume_fd_is_nonblocking", Nothing); return Val_long(ret); } CAMLprim value unix_writev_assume_fd_is_nonblocking_stub( value v_fd, value v_iovecs, value v_count) { int count = Int_val(v_count); ssize_t ret; struct iovec *iovecs = caml_stat_alloc(sizeof(struct iovec) * count); int i = count - 1; for (; i >= 0; --i) { struct iovec *iovec = &iovecs[i]; value v_iovec = Field(v_iovecs, i); value v_iov_base = Field(v_iovec, 0); value v_iov_pos = Field(v_iovec, 1); value v_iov_len = Field(v_iovec, 2); iovec->iov_base = String_val(v_iov_base) + Long_val(v_iov_pos); iovec->iov_len = Long_val(v_iov_len); } ret = writev(Int_val(v_fd), iovecs, count); caml_stat_free(iovecs); if (ret == -1) uerror("unix_writev_assume_fd_is_nonblocking", Nothing); return Val_long(ret); } CAMLprim value unix_writev_stub(value v_fd, value v_iovecs, value v_count) { int i, count = Int_val(v_count), len = 0; ssize_t ret; char *buf, *dst; for (i = count - 1; i >= 0; --i) { value v_iovec = Field(v_iovecs, i); value v_iov_len = Field(v_iovec, 2); len += Long_val(v_iov_len); } buf = caml_stat_alloc(len); dst = buf + len; for (i = count - 1; i >= 0; --i) { value v_iovec = Field(v_iovecs, i); value v_iov_base = Field(v_iovec, 0); value v_iov_pos = Field(v_iovec, 1); value v_iov_len = Field(v_iovec, 2); size_t iov_len = Long_val(v_iov_len); dst -= iov_len; /* We need to copy all the strings because as soon as we release the lock the GC may move them */ memcpy(dst, String_val(v_iov_base) + Long_val(v_iov_pos), iov_len); } caml_enter_blocking_section(); ret = write(Int_val(v_fd), buf, len); caml_stat_free(buf); caml_leave_blocking_section(); if (ret == -1) uerror("unix_writev", Nothing); return Val_long(ret); } /* pselect */ typedef fd_set file_descr_set; static inline void fdlist_to_fdset(value fdlist, fd_set *fdset, int *maxfd) { value l; FD_ZERO(fdset); for (l = fdlist; l != Val_int(0); l = Field(l, 1)) { int fd = Int_val(Field(l, 0)); FD_SET(fd, fdset); if (fd > *maxfd) *maxfd = fd; } } static inline value fdset_to_fdlist(value fdlist, fd_set *fdset) { value l; value res = Val_int(0); Begin_roots2(l, res); for (l = fdlist; l != Val_int(0); l = Field(l, 1)) { int fd = Int_val(Field(l, 0)); if (FD_ISSET(fd, fdset)) { value newres = caml_alloc_small(2, 0); Field(newres, 0) = Val_int(fd); Field(newres, 1) = res; res = newres; } } End_roots(); return res; } static inline void decode_sigset(value vset, sigset_t * set) { sigemptyset(set); while (vset != Val_int(0)) { int sig = caml_convert_signal_number(Int_val(Field(vset, 0))); sigaddset(set, sig); vset = Field(vset, 1); } } CAMLprim value unix_pselect_stub( value v_rfds, value v_wfds, value v_efds, value v_timeout, value v_sigmask) { fd_set rfds, wfds, efds; double tm = Double_val(v_timeout); struct timespec ts; struct timespec *tsp; int maxfd = -1, ret; value v_res; sigset_t sigmask; decode_sigset(v_sigmask, &sigmask); Begin_roots3(v_rfds, v_wfds, v_efds); fdlist_to_fdset(v_rfds, &rfds, &maxfd); fdlist_to_fdset(v_wfds, &wfds, &maxfd); fdlist_to_fdset(v_efds, &efds, &maxfd); if (tm < 0.0) tsp = (struct timespec *) NULL; else { ts = timespec_of_double(tm); tsp = &ts; } caml_enter_blocking_section(); ret = pselect(maxfd + 1, &rfds, &wfds, &efds, tsp, &sigmask); caml_leave_blocking_section(); if (ret == -1) uerror("pselect", Nothing); v_rfds = fdset_to_fdlist(v_rfds, &rfds); v_wfds = fdset_to_fdlist(v_wfds, &wfds); v_efds = fdset_to_fdlist(v_efds, &efds); v_res = caml_alloc_small(3, 0); Field(v_res, 0) = v_rfds; Field(v_res, 1) = v_wfds; Field(v_res, 2) = v_efds; End_roots(); return v_res; } /* Clock functions */ #ifdef JSC_POSIX_TIMERS #define clockid_t_val(v_cl) ((clockid_t) Nativeint_val(v_cl)) CAMLprim value unix_clock_gettime(value v_cl) { struct timespec ts; if (clock_gettime(clockid_t_val(v_cl), &ts)) uerror("clock_gettime", Nothing); return caml_copy_double(timespec_to_double(ts)); } CAMLprim value unix_clock_settime(value v_cl, value v_t) { struct timespec ts = timespec_of_double(Double_val(v_t)); if (clock_settime(clockid_t_val(v_cl), &ts)) uerror("clock_settime", Nothing); return Val_unit; } CAMLprim value unix_clock_getres(value v_cl) { struct timespec ts; if (clock_getres(clockid_t_val(v_cl), &ts)) uerror("clock_getres", Nothing); return caml_copy_double(timespec_to_double(ts)); } /* Unfortunately, it is currently not possible to extract the POSIX thread id given the OCaml-thread id due to lack of support for this feature in the OCaml-runtime. The below function clearly does not do what is intended in the general case, but will probably usually do the right thing. */ static inline pthread_t pthread_t_val(value __unused v_tid) { return pthread_self(); } #if defined(JSC_THREAD_CPUTIME) CAMLprim value unix_pthread_getcpuclockid(value v_tid) { clockid_t c; if (pthread_getcpuclockid(pthread_t_val(v_tid), &c)) uerror("pthread_getcpuclockid", Nothing); return caml_copy_nativeint(c); } #endif #if defined(CLOCK_PROCESS_CPUTIME_ID) #define CLOCK CLOCK_PROCESS_CPUTIME_ID #elif defined(CLOCK_PROF) #define CLOCK CLOCK_PROF #else #define CLOCK CLOCK_REALTIME #endif CAMLprim value unix_clock_process_cputime_id_stub(value __unused v_unit) { return caml_copy_nativeint(CLOCK); } CAMLprim value unix_clock_thread_cputime_id_stub(value __unused v_unit) { return caml_copy_nativeint(CLOCK); } #undef CLOCK #else #warning "posix timers not present; clock functions undefined" #endif /* Resource limits */ static inline int resource_val(value v_resource) { int resource; switch (Int_val(v_resource)) { case 0 : resource = RLIMIT_CORE; break; case 1 : resource = RLIMIT_CPU; break; case 2 : resource = RLIMIT_DATA; break; case 3 : resource = RLIMIT_FSIZE; break; case 4 : resource = RLIMIT_NOFILE; break; case 5 : resource = RLIMIT_STACK; break; #ifdef RLIMIT_AS case 6 : resource = RLIMIT_AS; break; #endif #ifdef RLIMIT_NICE case 7 : resource = RLIMIT_NICE; break; #endif default : /* impossible */ caml_failwith("resource_val: unknown sum tag"); break; } return resource; } static inline rlim_t rlim_t_val(value v_lim) { return Is_block(v_lim) ? (rlim_t) Int64_val(Field(v_lim, 0)) : RLIM_INFINITY; } static value Val_rlim_t(rlim_t lim) { value v_rl; if (lim == RLIM_INFINITY) v_rl = Val_int(0); else { value v_arg = caml_copy_int64(lim); Begin_roots1(v_arg); v_rl = caml_alloc_small(1, 0); End_roots(); Field(v_rl, 0) = v_arg; } return v_rl; } CAMLprim value unix_getrlimit(value v_resource) { CAMLparam0(); CAMLlocal2(v_cur, v_max); int resource = resource_val(v_resource); value v_limits; struct rlimit rl; if (getrlimit(resource, &rl)) uerror("getrlimit", Nothing); v_cur = Val_rlim_t(rl.rlim_cur); v_max = Val_rlim_t(rl.rlim_max); v_limits = caml_alloc_small(2, 0); Field(v_limits, 0) = v_cur; Field(v_limits, 1) = v_max; CAMLreturn(v_limits); } CAMLprim value unix_setrlimit(value v_resource, value v_limits) { struct rlimit rl; int resource = resource_val(v_resource); value v_cur = Field(v_limits, 0), v_max = Field(v_limits, 1); rl.rlim_cur = rlim_t_val(v_cur); rl.rlim_max = rlim_t_val(v_max); if (setrlimit(resource, &rl)) uerror("setrlimit", Nothing); return Val_unit; } /* Populating the ifreq structure is wiley and we do it in a couple of places, so lets factor it out here for safety. */ static struct ifreq build_ifaddr_request(const char *interface) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); assert(sizeof(ifr.ifr_name) == IFNAMSIZ); if (ifr.ifr_name[IFNAMSIZ-1] != '\0') caml_failwith("build_ifaddr_request: interface name string too long"); return ifr; } /* return a simple [in_addr] as the address */ struct in_addr core_unix_get_in_addr_for_interface(value v_interface) { int fd = -1; char* error = NULL; struct ifreq ifr = build_ifaddr_request(String_val(v_interface)); /* Note that [v_interface] is invalid past this point. */ caml_enter_blocking_section(); fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) error = "linux_get_ipv4_address_for_interface: couldn't allocate socket"; else { if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) error = "linux_get_ipv4_address_for_interface: ioctl(fd, SIOCGIFADDR, ...) failed"; (void) core_unix_close_durably(fd); } caml_leave_blocking_section(); if (error == NULL) { /* This is weird but doing the usual casting causes errors when using * the new gcc on CentOS 6. This solution was picked up on Red Hat's * bugzilla or something. It also works to memcpy a sockaddr into * a sockaddr_in. This is faster hopefully. */ union { struct sockaddr sa; struct sockaddr_in sain; } u; u.sa = ifr.ifr_addr; return u.sain.sin_addr; } uerror(error, Nothing); assert(0); /* [uerror] should never return. */ } /* Resource usage */ CAMLprim value unix_getrusage(value v_who) { CAMLparam0(); CAMLlocal1(v_usage); int who = (Int_val(v_who) == 0) ? RUSAGE_SELF : RUSAGE_CHILDREN; struct rusage ru; if (getrusage(who, &ru)) uerror("getrusage", Nothing); v_usage = caml_alloc(16, 0); Store_field(v_usage, 0, caml_copy_double((double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1e6)); Store_field(v_usage, 1, caml_copy_double((double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1e6)); Store_field(v_usage, 2, caml_copy_int64(ru.ru_maxrss)); Store_field(v_usage, 3, caml_copy_int64(ru.ru_ixrss)); Store_field(v_usage, 4, caml_copy_int64(ru.ru_idrss)); Store_field(v_usage, 5, caml_copy_int64(ru.ru_isrss)); Store_field(v_usage, 6, caml_copy_int64(ru.ru_minflt)); Store_field(v_usage, 7, caml_copy_int64(ru.ru_majflt)); Store_field(v_usage, 8, caml_copy_int64(ru.ru_nswap)); Store_field(v_usage, 9, caml_copy_int64(ru.ru_inblock)); Store_field(v_usage, 10, caml_copy_int64(ru.ru_oublock)); Store_field(v_usage, 11, caml_copy_int64(ru.ru_msgsnd)); Store_field(v_usage, 12, caml_copy_int64(ru.ru_msgrcv)); Store_field(v_usage, 13, caml_copy_int64(ru.ru_nsignals)); Store_field(v_usage, 14, caml_copy_int64(ru.ru_nvcsw)); Store_field(v_usage, 15, caml_copy_int64(ru.ru_nivcsw)); CAMLreturn(v_usage); } /* System configuration */ CAMLprim value unix_sysconf(value v_name) { int name; long ret; switch (Int_val(v_name)) { case 0 : name = _SC_ARG_MAX; break; case 1 : name = _SC_CHILD_MAX; break; case 2 : name = _SC_HOST_NAME_MAX; break; case 3 : name = _SC_LOGIN_NAME_MAX; break; case 4 : name = _SC_OPEN_MAX; break; case 5 : name = _SC_PAGESIZE; break; case 6 : name = _SC_RE_DUP_MAX; break; case 7 : name = _SC_STREAM_MAX; break; case 8 : name = _SC_SYMLOOP_MAX; break; case 9 : name = _SC_TTY_NAME_MAX; break; case 10 : name = _SC_TZNAME_MAX; break; case 11 : name = _SC_VERSION; break; /* We think this might work on Solaris, too, but don't have any boxes around to test it with. */ #if defined(__linux__) case 12 : name = _SC_PHYS_PAGES; break; case 13 : name = _SC_AVPHYS_PAGES; break; #endif case 14 : name = _SC_IOV_MAX; break; default : /* impossible */ caml_failwith("unix_sysconf: unknown sum tag"); break; } ret = sysconf(name); if (ret == -1) uerror("sysconf", Nothing); return (caml_copy_int64(ret)); } /* POSIX thread functions */ #define Mutex_val(v) (* ((pthread_mutex_t **) Data_custom_val(v))) #define Condition_val(v) (* ((pthread_cond_t **) Data_custom_val(v))) static void caml_pthread_check(int retcode, char *msg) { #define err_buf_len 100 char err_buf[err_buf_len]; char *err; size_t errlen, msglen; value str; if (retcode == 0) return; #ifdef __GLIBC__ err = strerror_r(retcode, err_buf, err_buf_len); #else if (strerror_r(retcode, err_buf, err_buf_len) == -1) uerror("strerror_r", Nothing); err = err_buf; #endif msglen = strlen(msg); errlen = strlen(err); str = caml_alloc_string(msglen + 2 + errlen); memmove(&Byte(str, 0), msg, msglen); memmove(&Byte(str, msglen), ": ", 2); memmove(&Byte(str, msglen + 2), err, errlen); caml_raise_sys_error(str); #undef err_buf_len } #if defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS > 0) CAMLprim value unix_mutex_timedlock(value v_mtx, value v_timeo) { int ret; pthread_mutex_t *mtx = Mutex_val(v_mtx); ret = pthread_mutex_trylock(mtx); if (ret == EBUSY) { struct timespec ts = timespec_of_double(Double_val(v_timeo)); Begin_roots1(v_mtx); caml_enter_blocking_section(); ret = pthread_mutex_timedlock(mtx, &ts); caml_leave_blocking_section(); End_roots(); if (ret == ETIMEDOUT) return Val_false; } caml_pthread_check(ret, "Mutex.timedlock"); return Val_true; } #else #warning "POSIX TMO not present; unix_mutex_timedlock undefined" #endif CAMLprim value unix_condition_timedwait(value v_cnd, value v_mtx, value v_timeo) { CAMLparam2(v_cnd, v_mtx); int ret; pthread_cond_t *cnd = Condition_val(v_cnd); pthread_mutex_t *mtx = Mutex_val(v_mtx); struct timespec ts = timespec_of_double(Double_val(v_timeo)); caml_enter_blocking_section(); ret = pthread_cond_timedwait(cnd, mtx, &ts); caml_leave_blocking_section(); if (ret == ETIMEDOUT) CAMLreturn(Val_false); caml_pthread_check(ret, "Condition.timedwait"); CAMLreturn(Val_true); } static void caml_mutex_finalize(value v_mtx) { pthread_mutex_t *mtx = Mutex_val(v_mtx); pthread_mutex_destroy(mtx); caml_stat_free(mtx); } static int caml_mutex_condition_compare(value v_mtx1, value v_mtx2) { pthread_mutex_t *mtx1 = Mutex_val(v_mtx1); pthread_mutex_t *mtx2 = Mutex_val(v_mtx2); return mtx1 == mtx2 ? 0 : mtx1 < mtx2 ? -1 : 1; } static struct custom_operations caml_mutex_ops = { "_mutex", caml_mutex_finalize, caml_mutex_condition_compare, custom_hash_default, custom_serialize_default, custom_deserialize_default, # ifdef custom_compare_ext_default custom_compare_ext_default #endif }; #if defined(_POSIX_THREADS) && _POSIX_THREADS >= 200112L CAMLprim value unix_create_error_checking_mutex(value __unused v_unit) { pthread_mutex_t *mtx; pthread_mutexattr_t attrs; value v_res; pthread_mutexattr_init(&attrs); pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_ERRORCHECK); mtx = caml_stat_alloc(sizeof(pthread_mutex_t)); caml_pthread_check( pthread_mutex_init(mtx, &attrs), "Mutex.create_error_checking"); pthread_mutexattr_destroy(&attrs); v_res = caml_alloc_custom(&caml_mutex_ops, sizeof(pthread_mutex_t *), 1, 1000); Mutex_val(v_res) = mtx; return v_res; } #else #warning "_POSIX_THREADS not defined or < 200112; unix_create_error_checking_mutex not available" #endif /* Pathname resolution */ /* Seems like a sane approach to getting a reasonable bound for the maximum path length */ #ifdef PATH_MAX #define JANE_PATH_MAX ((PATH_MAX <= 0 || PATH_MAX > 65536) ? 65536 : PATH_MAX) #else #define JANE_PATH_MAX (65536) #endif #ifdef __GLIBC__ CAMLprim value unix_realpath(value v_path) { char *path = String_val(v_path); char *res = realpath(path, NULL); if (res == NULL) uerror("realpath", v_path); else { value v_res = caml_copy_string(res); free(res); return v_res; } } #else CAMLprim value unix_realpath(value v_path) { char *path = String_val(v_path); /* [realpath] is inherently broken without GNU-extension, and this seems like a reasonable thing to do if we do not build against GLIBC. */ char resolved_path[JANE_PATH_MAX]; if (realpath(path, resolved_path) == NULL) uerror("realpath", v_path); return caml_copy_string(resolved_path); } #endif /* Temporary file and directory creation */ static inline void init_mktemp(char *loc, char *buf, value v_path) { int i, len = caml_string_length(v_path); if (len > JANE_PATH_MAX - 7) caml_invalid_argument(loc); memcpy(buf, String_val(v_path), len); for (i = len; i < len + 6; ++i) buf[i] = 'X'; buf[len + 6] = '\0'; } CAMLprim value unix_mkstemp(value v_path) { CAMLparam1(v_path); CAMLlocal1(v_res_path); char *loc = "mkstemp"; char buf[JANE_PATH_MAX]; int fd; value v_res; init_mktemp(loc, buf, v_path); caml_enter_blocking_section(); fd = mkstemp(buf); caml_leave_blocking_section(); if (fd == -1) uerror(loc, v_path); v_res_path = caml_copy_string(buf); v_res = caml_alloc_small(2, 0); Field(v_res, 0) = v_res_path; Field(v_res, 1) = Val_int(fd); CAMLreturn(v_res); } CAMLprim value unix_mkdtemp(value v_path) { CAMLparam1(v_path); char *loc = "mkdtemp"; char *path; char buf[JANE_PATH_MAX]; init_mktemp(loc, buf, v_path); caml_enter_blocking_section(); path = mkdtemp(buf); caml_leave_blocking_section(); if (path == NULL) uerror(loc, v_path); CAMLreturn(caml_copy_string(buf)); } /* Signal handling */ CAMLprim value unix_abort(value v_unit) { abort(); return v_unit; } /* User id, group id management */ CAMLprim value unix_initgroups(value v_user, value v_group) { int ret, user_len = caml_string_length(v_user) + 1; char *c_user = caml_stat_alloc(user_len); gid_t group = Long_val(v_group); memcpy(c_user, String_val(v_user), user_len); caml_enter_blocking_section(); ret = initgroups(c_user, group); caml_stat_free(c_user); caml_leave_blocking_section(); if (ret == -1) uerror("initgroups", Nothing); return Val_unit; } CAMLprim value unix_getgrouplist(value v_user, value v_group) { int n; int ngroups = NGROUPS_MAX; gid_t groups[NGROUPS_MAX]; value ret; char *c_user; assert(Is_block(v_user) && Tag_val(v_user) == String_tag); assert(!Is_block(v_group)); c_user = strdup(String_val(v_user)); caml_enter_blocking_section(); n = getgrouplist(c_user, Long_val(v_group), groups, &ngroups); free(c_user); caml_leave_blocking_section(); if (n == -1) uerror ("getgrouplist", Nothing); ret = caml_alloc_small(n, 0); for (n = n - 1; n >= 0; n--) Field(ret, n) = Val_long(groups[n]); return ret; } /* Globbing and shell string expansion */ CAMLprim value unix_fnmatch_make_flags(value v_flags) { int flags = 0, i = Wosize_val(v_flags); while (--i >= 0) { switch (Int_val(Field(v_flags, i))) { case 0 : flags |= FNM_NOESCAPE; break; case 1 : flags |= FNM_PATHNAME; break; case 2 : flags |= FNM_PERIOD; break; case 3 : flags |= FNM_PATHNAME; break; case 4 : flags |= FNM_LEADING_DIR; break; default : flags |= FNM_CASEFOLD; break; } } return caml_copy_int32(flags); } CAMLprim value unix_fnmatch(value v_flags, value v_glob, value v_str) { int flags = Int32_val(v_flags); char *glob = String_val(v_glob); char *str = String_val(v_str); int ret = fnmatch(glob, str, flags); switch (ret) { case 0 : return Val_true; case FNM_NOMATCH : return Val_false; default : caml_failwith("fnmatch"); } } #if defined(JSC_WORDEXP) CAMLprim value unix_wordexp_make_flags(value v_flags) { int flags = 0, i = Wosize_val(v_flags); while (--i >= 0) { switch (Int_val(Field(v_flags, i))) { case 0 : flags |= WRDE_NOCMD; break; case 1 : flags |= WRDE_SHOWERR; break; default : flags |= WRDE_UNDEF; break; } } return caml_copy_int32(flags); } CAMLprim value unix_wordexp(value v_flags, value v_str) { CAMLparam0(); CAMLlocal1(v_res); int flags = Int32_val(v_flags); unsigned int i, len = caml_string_length(v_str) + 1; int ret; char *buf = caml_stat_alloc(len); char **w; wordexp_t p; memcpy(buf, String_val(v_str), len); caml_enter_blocking_section(); ret = wordexp(buf, &p, flags); caml_stat_free(buf); caml_leave_blocking_section(); switch (ret) { case 0 : v_res = caml_alloc(p.we_wordc, 0); w = p.we_wordv; for (i = 0; i < p.we_wordc; ++i) Store_field(v_res, i, caml_copy_string(w[i])); wordfree(&p); CAMLreturn(v_res); case WRDE_BADCHAR : caml_failwith("wordexp: bad char"); case WRDE_BADVAL : caml_failwith("wordexp: undefined shell variable"); case WRDE_CMDSUB : caml_failwith("wordexp: unwanted command substitution"); case WRDE_NOSPACE : caml_failwith("wordexp: out of memory"); case WRDE_SYNTAX : caml_failwith("wordexp: syntax error"); default : caml_failwith("wordexp: impossible"); } } #endif /* defined(JSC_WORDEXP) */ /* System information */ CAMLprim value unix_uname(value v_unit __unused) { CAMLparam0(); CAMLlocal1(v_utsname); struct utsname u; if (uname(&u)) uerror("uname", Nothing); v_utsname = caml_alloc(5, 0); Store_field(v_utsname, 0, caml_copy_string(u.sysname)); Store_field(v_utsname, 1, caml_copy_string(u.nodename)); Store_field(v_utsname, 2, caml_copy_string(u.release)); Store_field(v_utsname, 3, caml_copy_string(u.version)); Store_field(v_utsname, 4, caml_copy_string(u.machine)); CAMLreturn(v_utsname); } /* Additional IP functionality */ CAMLprim value unix_if_indextoname(value v_index) { char name[IF_NAMESIZE]; if (if_indextoname((unsigned int) Int_val(v_index), name) == NULL) uerror("if_indextoname", Nothing); else return caml_copy_string(name); } #include "socketaddr.h" /* Keep this in sync with the type Core_unix.Mcast_action.t */ #define VAL_MCAST_ACTION_ADD (Val_int(0)) #define VAL_MCAST_ACTION_DROP (Val_int(1)) CAMLprim value core_unix_mcast_modify (value v_action, value v_ifname_opt, value v_source_opt, value v_fd, value v_sa) { int ret, fd = Int_val(v_fd); union sock_addr_union sau; struct sockaddr *sa = &sau.s_gen; socklen_param_type sa_len; get_sockaddr(v_sa, &sau, &sa_len); switch (sa->sa_family) { case AF_INET: { struct ip_mreq mreq; memcpy(&mreq.imr_multiaddr, &((struct sockaddr_in *) sa)->sin_addr, sizeof(struct in_addr)); if (Is_block(v_ifname_opt)) { struct ifreq ifreq; assert(Tag_val(v_ifname_opt) == 0 && Wosize_val(v_ifname_opt) == 1); ifreq = build_ifaddr_request(String_val(Field(v_ifname_opt,0))); if (ioctl(fd, SIOCGIFADDR, &ifreq) < 0) uerror("core_unix_mcast_modify: ioctl", Nothing); memcpy(&mreq.imr_interface, &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr, sizeof(struct in_addr)); } else { assert(v_ifname_opt == Val_long(0) /* None */); mreq.imr_interface.s_addr = htonl(INADDR_ANY); } if (Is_block(v_source_opt)) { #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) caml_failwith("core_unix_mcast_modify: ~source is not supported on MacOS, OpenBSD or NetBSD"); #else struct ip_mreq_source mreq_source; assert(v_action == VAL_MCAST_ACTION_ADD); assert(Tag_val(v_source_opt) == 0 && Wosize_val(v_source_opt) == 1); mreq_source.imr_multiaddr = mreq.imr_multiaddr; mreq_source.imr_interface = mreq.imr_interface; mreq_source.imr_sourceaddr = GET_INET_ADDR(Field(v_source_opt, 0)); ret = setsockopt(fd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, &mreq_source, sizeof(mreq_source)); #endif } else { int optname; assert(v_source_opt == Val_long(0) /* None */); switch (v_action) { case VAL_MCAST_ACTION_ADD: optname = IP_ADD_MEMBERSHIP; break; case VAL_MCAST_ACTION_DROP: optname = IP_DROP_MEMBERSHIP; break; default: caml_failwith("core_unix_mcast_modify: invalid action"); } ret = setsockopt(fd, IPPROTO_IP, optname, &mreq, sizeof(mreq)); } if (ret == -1) uerror("core_unix_mcast_modify: setsockopt", Nothing); return Val_unit; } default: unix_error(EPROTONOSUPPORT, "core_unix_mcast_modify", Nothing); } } /* Similar to it's use in linux_ext, these are unfortunately not exported presently. It seems we should either get the functions exported, or have all portable ip level options (such as IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_TTL, IP_MULTICAST_LOOP, and IP_MULTICAST_IF) added to the stdlib. */ enum option_type { TYPE_BOOL = 0, TYPE_INT = 1, TYPE_LINGER = 2, TYPE_TIMEVAL = 3, TYPE_UNIX_ERROR = 4 }; extern value unix_getsockopt_aux( char *name, enum option_type ty, int level, int option, value v_socket); extern value unix_setsockopt_aux( char *name, enum option_type ty, int level, int option, value v_socket, value v_status); CAMLprim value unix_mcast_get_ttl(value v_socket) { return unix_getsockopt_aux("getsockopt", TYPE_INT, IPPROTO_IP, IP_MULTICAST_TTL, v_socket); } CAMLprim value unix_mcast_set_ttl(value v_socket, value v_ttl) { return unix_setsockopt_aux( "setsockopt", TYPE_INT, IPPROTO_IP, IP_MULTICAST_TTL, v_socket, v_ttl); } CAMLprim value unix_mcast_set_ifname(value v_socket, value v_ifname) { struct in_addr addr; assert(!Is_block(v_socket)); /* Here is the IPv4 address of the ethernet interface. */ addr = core_unix_get_in_addr_for_interface(v_ifname); /* Now setsockopt to publish on the interface using the address. */ return unix_setsockopt_aux("setsockopt", TYPE_INT, IPPROTO_IP, IP_MULTICAST_IF, v_socket, Val_int(addr.s_addr)); } CAMLprim value unix_mcast_get_loop(value v_socket) { return unix_getsockopt_aux("getsockopt", TYPE_BOOL, IPPROTO_IP, IP_MULTICAST_LOOP, v_socket); } CAMLprim value unix_mcast_set_loop(value v_socket, value v_loop) { return unix_setsockopt_aux( "setsockopt", TYPE_BOOL, IPPROTO_IP, IP_MULTICAST_LOOP, v_socket, v_loop); } /* Scheduling */ #if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING+0 > 0) static int sched_policy_table[] = { SCHED_FIFO, SCHED_RR, SCHED_OTHER }; CAMLprim value unix_sched_setscheduler( value v_pid, value v_policy, value v_priority) { struct sched_param sched_param; int pid = Int_val(v_pid); int policy = sched_policy_table[Int_val(v_policy)]; int priority = Int_val(v_priority); if (sched_getparam(pid, &sched_param) != 0) uerror("sched_getparam", Nothing); sched_param.sched_priority = priority; if (sched_setscheduler(pid, policy, &sched_param) != 0) uerror("sched_setscheduler", Nothing); return Val_unit; } #else #warning "_POSIX_PRIORITY_SCHEDULING not present; sched_setscheduler undefined" CAMLprim value unix_sched_setscheduler( value __unused v_pid, value __unused v_policy, value __unused v_priority) { invalid_argument("sched_setscheduler unimplemented"); } #endif /* Priority */ CAMLprim value unix_nice(value v_inc) { int new_nice; errno = 0; new_nice = nice(Int_val(v_inc)); if (new_nice == -1 && errno) uerror("nice", Nothing); else return Val_int(new_nice); } CAMLprim value unix_unsetenv(value var) { if (unsetenv(String_val(var)) != 0) uerror("unsetenv", var); return Val_unit; } static int mman_mcl_flags_table[] = { MCL_CURRENT, MCL_FUTURE }; CAMLprim value unix_mlockall(value v_flags) { CAMLparam1(v_flags); size_t i, mask; for (i = 0, mask = 0; i < Wosize_val(v_flags); i++) mask |= mman_mcl_flags_table[Int_val(Field(v_flags, i))]; if (mlockall(mask) < 0) uerror("mlockall", Nothing); CAMLreturn(Val_unit); } CAMLprim value unix_munlockall() { if (munlockall() < 0) uerror("munlockall", Nothing); return Val_unit; } static value alloc_tm(struct tm *tm) { value res; res = caml_alloc_small(9, 0); Field(res,0) = Val_int(tm->tm_sec); Field(res,1) = Val_int(tm->tm_min); Field(res,2) = Val_int(tm->tm_hour); Field(res,3) = Val_int(tm->tm_mday); Field(res,4) = Val_int(tm->tm_mon); Field(res,5) = Val_int(tm->tm_year); Field(res,6) = Val_int(tm->tm_wday); Field(res,7) = Val_int(tm->tm_yday); Field(res,8) = tm->tm_isdst ? Val_true : Val_false; return res; } CAMLprim value unix_strptime(value v_fmt, value v_s) { CAMLparam2(v_s, v_fmt); struct tm tm; tm.tm_sec = 0; tm.tm_min = 0; tm.tm_hour = 0; tm.tm_mday = 0; tm.tm_mon = 0; tm.tm_year = 0; tm.tm_wday = 0; tm.tm_yday = 0; tm.tm_isdst = 0; if (strptime(String_val(v_s), String_val(v_fmt), &tm) == NULL) caml_failwith("unix_strptime: match failed"); CAMLreturn(alloc_tm(&tm)); } CAMLprim value core_unix_remove(value v_path) { CAMLparam1(v_path); int retval; char *path = core_copy_to_c_string(v_path); caml_enter_blocking_section(); retval = remove(path); caml_stat_free(path); caml_leave_blocking_section(); if (retval) uerror("remove", v_path); CAMLreturn(Val_unit); } #if defined(JSC_LINUX_EXT) #include CAMLprim value unix_gettid(value v_unit __unused) { return Val_long(syscall(SYS_gettid)); } #elif defined(__OpenBSD__) /* Advice from Philip Guenther on the ocaml-core mailing list is that we need to prototype * this ourselves :( * See: https://groups.google.com/forum/#!topic/ocaml-core/51knlnuJ8MM */ extern pid_t getthrid(void); CAMLprim value unix_gettid(value v_unit __unused) { return Val_long(getthrid()); } #elif defined(JSC_THREAD_ID) #error "JSC_THREAD_ID defined, but no implementation available (misconfigured in discover.sh?)" #endif core-113.00.00/src/unix_time_stubs.c000066400000000000000000000067621256461075500171460ustar00rootroot00000000000000 #include #include #include #include #include #include #include #include #include #include "ocaml_utils.h" #include "timespec.h" #include "time_ns_stubs.h" /* Improved localtime implementation Addresses bug: http://caml.inria.fr/mantis/view.php?id=5193 */ #include #include static value alloc_tm(struct tm *tm) { value res; res = caml_alloc_small(9, 0); Field(res,0) = Val_int(tm->tm_sec); Field(res,1) = Val_int(tm->tm_min); Field(res,2) = Val_int(tm->tm_hour); Field(res,3) = Val_int(tm->tm_mday); Field(res,4) = Val_int(tm->tm_mon); Field(res,5) = Val_int(tm->tm_year); Field(res,6) = Val_int(tm->tm_wday); Field(res,7) = Val_int(tm->tm_yday); Field(res,8) = tm->tm_isdst ? Val_true : Val_false; return res; } /* * converts a tm structure to a float with the assumption that that the structure * defines a gmtime */ CAMLprim value core_timegm (value tm_val) { struct tm tm; time_t res; tm.tm_sec = Int_val(Field(tm_val,0)); tm.tm_min = Int_val(Field(tm_val,1)); tm.tm_hour = Int_val(Field(tm_val,2)); tm.tm_mday = Int_val(Field(tm_val,3)); tm.tm_mon = Int_val(Field(tm_val,4)); tm.tm_year = Int_val(Field(tm_val,5)); tm.tm_wday = Int_val(Field(tm_val,6)); tm.tm_yday = Int_val(Field(tm_val,7)); tm.tm_isdst = 0; /* tm_isdst is not used by timegm (which sets it to 0) */ tm.tm_gmtoff = 0; /* tm_gmtoff is not used by timegm (which sets it to 0) */ tm.tm_zone = NULL; res = timegm(&tm); if (res == (time_t) -1) caml_failwith("timegm"); return caml_copy_double((double) res); } CAMLprim value core_time_ns_strftime(value v_tm, value v_fmt) { struct tm tm; tm.tm_sec = Int_val(Field(v_tm, 0)); tm.tm_min = Int_val(Field(v_tm, 1)); tm.tm_hour = Int_val(Field(v_tm, 2)); tm.tm_mday = Int_val(Field(v_tm, 3)); tm.tm_mon = Int_val(Field(v_tm, 4)); tm.tm_year = Int_val(Field(v_tm, 5)); tm.tm_wday = Int_val(Field(v_tm, 6)); tm.tm_yday = Int_val(Field(v_tm, 7)); tm.tm_isdst = Bool_val(Field(v_tm, 8)); #ifdef __USE_BSD tm.tm_gmtoff = 0; /* GNU extension, may not be visible everywhere */ tm.tm_zone = NULL; /* GNU extension, may not be visible everywhere */ #endif return core_kernel_time_ns_format_tm(&tm, v_fmt); } CAMLprim value core_time_ns_nanosleep(value v_seconds) { struct timespec req = timespec_of_double(Double_val(v_seconds)); struct timespec rem; int retval; caml_enter_blocking_section(); retval = nanosleep(&req, &rem); caml_leave_blocking_section(); if (retval == 0) return caml_copy_double(0.0); else if (retval == -1) { if (errno == EINTR) return caml_copy_double(timespec_to_double(rem)); else uerror("nanosleep", Nothing); } else caml_failwith("core_time_ns_nanosleep: impossible return value from nanosleep(2)"); } /* * These are the same functions as the ones in ocaml except that they call * {localtime,gmtime}_r instead of {localtime,gmtime} to avoid setting the * global tzname (instead setting the tm_store value that we discard). */ #define WRAP_TIME_FUN(NAME, ERROR) \ CAMLprim value core_##NAME (value t) \ { \ time_t clock; \ struct tm *tm; \ struct tm tm_store; \ clock = (time_t) Double_val(t); \ tm = NAME##_r(&clock, &tm_store); \ if (tm == NULL) caml_failwith(ERROR); \ return alloc_tm(tm); \ } WRAP_TIME_FUN(localtime, "localtime") WRAP_TIME_FUN(gmtime, "gmtime") core-113.00.00/src/unix_utils.h000066400000000000000000000015111256461075500161200ustar00rootroot00000000000000#ifndef UNIX_UTILS_H #define UNIX_UTILS_H #define _GNU_SOURCE #include #include /* Utility definitions */ static inline char * get_bstr(value v_bstr, value v_pos) { return (char *) Caml_ba_data_val(v_bstr) + Long_val(v_pos); } static inline struct iovec * copy_iovecs(size_t *total_len, value v_iovecs, int n) { struct iovec *iovecs = caml_stat_alloc(sizeof(struct iovec) * n); for (--n; n >= 0; --n) { struct iovec *iovec = &iovecs[n]; value v_iovec = Field(v_iovecs, n); value v_iov_base = Field(v_iovec, 0); value v_iov_pos = Field(v_iovec, 1); size_t iov_len = Long_val(Field(v_iovec, 2)); iovec->iov_len = iov_len; *total_len += iov_len; iovec->iov_base = get_bstr(v_iov_base, v_iov_pos); } return iovecs; } #include #endif /* UNIX_UTILS_H */ core-113.00.00/src/unpack_buffer.ml000066400000000000000000000000421256461075500167060ustar00rootroot00000000000000include Core_kernel.Unpack_buffer core-113.00.00/src/user_and_group.ml000066400000000000000000000022771256461075500171240ustar00rootroot00000000000000open Core_kernel.Std module Stable = struct module V1 = struct module T = struct type t = { user : string; group : string } with fields, bin_io, compare let to_string t = sprintf "%s:%s" t.group t.user let of_string str = let user, group = String.lsplit2_exn str ~on:':' in if String.contains group ':' then failwithf ("User_and_group.of_string: malformed [%s]:" ^^ " unix group names may not contain colons") str (); { user; group } end include T include Sexpable.Of_stringable(T) end end module T' = struct include Stable.V1 let hash t = String.hash (to_string t) let module_name = "Core.Std.User_and_group" end include T' include Identifiable.Make (T') TEST = equal { user = "foo"; group = "bar" } (of_string "foo:bar") let create = Fields.create let for_this_process () = let user = Unix.getlogin () in let gid = Unix.getgid () in match Core_unix.Group.getbygid gid with | None -> Or_error.error "Couldn't get group" (`gid gid) <:sexp_of< [ `gid of int ] >> | Some group -> Ok (create ~user ~group:group.Core_unix.Group.name) let for_this_process_exn () = Or_error.ok_exn (for_this_process ()) core-113.00.00/src/user_and_group.mli000066400000000000000000000012541256461075500172670ustar00rootroot00000000000000(** A pair of unix username and primary unix group. *) open Core_kernel.Std type t (** The string/sexp converters follow the usual unix convention of ':'. *) include Identifiable.S with type t := t val create : user:string -> group:string -> t val user : t -> string val group : t -> string (** Get the [t] for the current process. If you're using async, there is a wrapper, [Async.Std.User_and_group], that doesn't do blocking calls. *) val for_this_process : unit -> t Or_error.t val for_this_process_exn : unit -> t module Stable : sig module V1 : sig type nonrec t = t with sexp, bin_io, compare include Stringable with type t := t end end core-113.00.00/src/uuid.ml000066400000000000000000000076571256461075500150650ustar00rootroot00000000000000(* A loose implementation of version 3 of the UUID spec: Version 3 UUIDs use a scheme deriving a UUID via MD5 from a URL, a fully qualified domain name, an object identifier, a distinguished name (DN as used in Lightweight Directory Access Protocol), or on names in unspecified namespaces. Version 3 UUIDs have the form xxxxxxxx-xxxx-3xxx-xxxx-xxxxxxxxxxxx with hexadecimal digits x. *) module Stable = struct open Core_kernel.Stable module V1 = struct type t = string with bin_io, compare, sexp let for_testing = "5a863fc1-67b7-3a0a-dc90-aca2995afbf9" end end open Core_kernel.Std module Unix = Core_unix (* The base module is responsible for generating unique string identifiers. It should be clear to a reader that the id generated has an extremely high probability of uniqueness across all possible machines, processes, and threads of execution. *) module Base = struct type t = { hostname : string; pid : Pid.t; time : Time.t; counter : int; } let next_counter = let counter = ref 0 in (fun () -> (* In OCaml this doesn't allocate, and threads can't context switch except on allocation *) incr counter; !counter) ;; let to_string t = String.concat ~sep:"-" [ t.hostname; Int.to_string (Pid.to_int t.pid); Float.to_string (Time.to_float t.time); Int.to_string t.counter ] ;; let create () = { hostname = Unix.gethostname (); pid = Unix.getpid (); time = Time.now (); counter = next_counter (); } ;; end module T = struct type t = string with bin_io let create () = let digest = Digest.to_hex (Digest.string (Base.to_string (Base.create ()))) in let s = String.create 36 in s.[8] <- '-'; s.[13] <- '-'; s.[18] <- '-'; s.[23] <- '-'; String.blit ~src:digest ~dst:s ~src_pos:0 ~dst_pos:0 ~len:8; String.blit ~src:digest ~dst:s ~src_pos:8 ~dst_pos:9 ~len:4; String.blit ~src:digest ~dst:s ~src_pos:12 ~dst_pos:14 ~len:4; String.blit ~src:digest ~dst:s ~src_pos:16 ~dst_pos:19 ~len:4; String.blit ~src:digest ~dst:s ~src_pos:20 ~dst_pos:24 ~len:12; s.[14] <- '3'; s ;; let to_string = ident let of_string s = match String.split ~on:'-' s with | [a; b; c; d; e] -> begin try assert (String.length a = 8); assert (String.length b = 4); assert (String.length c = 4); assert (String.length d = 4); assert (String.length e = 12); (* we don't check for a 3 in the version position (14) because we want to be generous about accepting UUIDs generated by other versions of the protocol, and we want to be resilient to future changes in this algorithm. *) s with | _ -> failwithf "%s: not a valid UUID" s () end | _ -> failwithf "%s: not a valid UUID" s () ;; end include T include Identifiable.Make (struct let module_name = "Core.Std.Uuid" include T include Sexpable.Of_stringable (T) let compare t1 t2 = String.compare t1 t2 let hash t = String.hash t end) let invariant t = ignore (of_string t : t) module Test = struct let test_size = 100_000 let no_collisions l = let rec loop set l = match l with | [] -> true | t :: rest -> if Set.mem set t then false else loop (Set.add set t) rest in loop Set.empty l ;; let generate (n:int) = let rec loop acc n = if Int.(=) n 0 then acc else loop (create () :: acc) (n - 1) in loop [] n ;; let thread_test () = let res1 = ref [] in let res2 = ref [] in let thread1 = Thread.create (fun () -> res1 := generate test_size) () in let thread2 = Thread.create (fun () -> res2 := generate test_size) () in Thread.join thread1; Thread.join thread2; no_collisions (List.rev_append !res1 !res2) ;; TEST = no_collisions (generate test_size) TEST = thread_test () end core-113.00.00/src/uuid.mli000066400000000000000000000010301256461075500152110ustar00rootroot00000000000000(** Implements universally unique identifiers based on version 3 of the UUID specification. Identifier generation is thread safe, and fast. *) open Core_kernel.Std type t with sexp include Identifiable.S with type t := t include Invariant.S with type t := t (** [create ()] returns a new [t] guaranteed to not be equal to any other UUID generated by any process anywhere. *) val create : unit -> t module Stable : sig module V1 : sig type nonrec t = t with bin_io, compare, sexp val for_testing : t end end core-113.00.00/src/validate.ml000066400000000000000000000000351256461075500156670ustar00rootroot00000000000000include Core_kernel.Validate core-113.00.00/src/version_defaults.mlh000066400000000000000000000001301256461075500176160ustar00rootroot00000000000000DEFINE DEFAULT_VERSION = "No version info." DEFINE DEFAULT_BUILDINFO = "No build info." core-113.00.00/src/version_util.mli000066400000000000000000000037431256461075500170020ustar00rootroot00000000000000(** This module gives access to the same version/build information returned by [Command]-based executables when called with the [-version] or [-build-info] flags by [$0 version (-build-info | -version)] or [$0 (-build-info | -version)]. Here's how it works: we arrange for the build system to, at link time, include an object file that defines symbols that version_util.ml uses to get the strings that contain the information that this module provides. When building with OMake, our OMakeroot runs build_info.sh to generate *.build_info.c with the symbols and that is linked in. *) open Std_internal val version : string val version_list : string list val arg_spec : (string * Core_arg.spec * string) list (** [Application_specific_fields] is a single field in the build-info sexp that holds a [Sexp.t String.Map.t], which can be chosen by the application to hold custom fields that it needs. *) module Application_specific_fields : sig type t = Sexp.t String.Map.t with sexp (** [putenv t] stores [t] in the process environment so that build_info.sh will see it. One calls [putenv t] in a program before calling OMake to set the appropriate environment variable so that the application-specific fields in the program being compiled will have value [t]. That is, one calls [putenv] in the program building the application and [Version_util.application_specific_fields] in the application itself. *) val putenv : t -> unit end val build_info : string val build_info_as_sexp : Sexp.t val username : string val hostname : string val kernel : string val time : Time.t val x_library_inlining : bool val compiled_for_speed : bool val application_specific_fields : Application_specific_fields.t option val ocaml_version : string val executable_path : string (** Relative to OMakeroot dir *) core-113.00.00/src/weak_hashtbl.ml000066400000000000000000000103451256461075500165370ustar00rootroot00000000000000open Core_kernel.Std module Entry = struct type 'a t = 'a Weak.t with sexp_of let create () = Weak.create ~len:1 let data t = Weak.get t 0 let set_data t data = Weak.set t 0 (Some data) let is_in_use t = Weak.is_some t 0 end type ('a, 'b) t = { entry_by_key : ('a, 'b Entry.t) Hashtbl.t ; keys_with_unused_data : 'a Thread_safe_queue.t ; mutable thread_safe_run_when_unused_data : unit -> unit } with sexp_of let create ?growth_allowed ?size hashable = { entry_by_key = Hashtbl.create ~hashable ?growth_allowed ?size () ; keys_with_unused_data = Thread_safe_queue.create () ; thread_safe_run_when_unused_data = ignore } ;; let set_run_when_unused_data t ~thread_safe_f = t.thread_safe_run_when_unused_data <- thread_safe_f; ;; let remove t key = Hashtbl.remove t.entry_by_key key (* In order for a call to [reclaim_space_for_keys_with_unused_data] to reclaim a key that was previously finalized, the weak pointer must have been cleared. This relies on the fact that the OCaml garbage collector clears weaks and then runs finalizers. *) let reclaim_space_for_keys_with_unused_data t = while Thread_safe_queue.length t.keys_with_unused_data > 0 do let key = Thread_safe_queue.dequeue_exn t.keys_with_unused_data in match Hashtbl.find t.entry_by_key key with | None -> () | Some entry -> if not (Entry.is_in_use entry) then remove t key done; ;; let get_entry t key = Hashtbl.find_or_add t.entry_by_key key ~default:Entry.create let mem t key = match Hashtbl.find t.entry_by_key key with | None -> false | Some entry -> Entry.is_in_use entry ;; let key_is_using_space t key = Hashtbl.mem t.entry_by_key key let set_data t key entry data = Entry.set_data entry data; Gc.Expert.add_finalizer data (fun _ -> Thread_safe_queue.enqueue t.keys_with_unused_data key; t.thread_safe_run_when_unused_data ()); ;; let replace t ~key ~data = set_data t key (get_entry t key) data let add_exn t ~key ~data = let entry = get_entry t key in if Entry.is_in_use entry then failwiths "Weak_hashtbl.add_exn of key in use" t <:sexp_of< (_, _) t >>; set_data t key entry data; ;; let find t key = match Hashtbl.find t.entry_by_key key with | None -> None | Some entry -> Entry.data entry ;; let find_or_add t key ~default = let entry = get_entry t key in match Entry.data entry with | Some v -> v | None -> let data = default () in set_data t key entry data; data ;; TEST_UNIT = let module M = struct type t = (* [mutable foo] to force the compiler to allocate the record on the heap. *) { mutable foo : int ; bar : int ; baz : string } end in let open M in let block foo = Heap_block.create_exn ({ foo; bar = 0; baz = "hello" }, 0) in let tbl = create Int.hashable in let stabilize () = Gc.full_major (); reclaim_space_for_keys_with_unused_data tbl; in let add k b = ignore (find_or_add tbl k ~default:(fun () -> !b)) in (* We put the blocks in refs and manually blackhole them, so that the unit test will pass with the bytecode compiler. *) let b1 = ref (block 1) in let b2 = ref (block 2) in let b3 = ref (block 3) in let b4 = ref (block 4) in let blackhole b = b := block 0 in let k1 = 1 in let k2 = 2 in let k3 = 3 in add k1 b1; add k2 b2; add k3 b3; (* Checking [is_absent k] is stronger than checking that [is_none (find tbl k)]. We want to make sure that a key has been removed from the table, and in particular rule out the case where the key is in the table but the corresponding weak is none. *) let is_absent k = not (key_is_using_space tbl k) in let is_block k b = match find tbl k with | None -> false | Some v -> phys_equal v b in assert (is_block k1 !b1); assert (is_block k2 !b2); assert (is_block k3 !b3); blackhole b1; stabilize (); assert (is_absent k1); assert (is_block k2 !b2); assert (is_block k3 !b3); blackhole b2; stabilize (); assert (is_absent k1); assert (is_absent k2); assert (is_block k3 !b3); replace tbl ~key:k3 ~data:!b4; blackhole b3; stabilize (); assert (is_block k3 !b4); blackhole b4; stabilize (); assert (is_absent k3); ;; core-113.00.00/src/weak_hashtbl.mli000066400000000000000000000057371256461075500167210ustar00rootroot00000000000000(** A hashtable that keeps a weak pointer to each key's data and uses a finalizer to detect when the data is no longer referenced (by any non-weak pointers). Once a key's data is finalized, the table will effectively behave as if the key is not in the table, e.g. [find] will return [None]. However, one must call [reclaim_space_for_keys_with_unused_data] to actually reclaim the space used by the table for such keys. Unlike (OCaml's) [Weak.Make], which also describes itself as a "weak hashtable," [Weak_hashtbl] gives a dictionary style structure. In fact, OCaml's [Weak.Make] may better be described as a weak set. There's a tricky type of bug one can write with this module, e.g.: {[ type t = { foo : string ; bar : float Incr.t } let tbl = Weak_hashtbl.create () let x1 = let t = Weak_hashtbl.find_or_add tbl key ~default:(fun () -> (... some function that computes a t...)) in t.bar ]} At this point, the data associated with [key] is unreachable (since all we did with it was project out field bar), so it may disappear from the table at any time. *) open Core_kernel.Std type ('a, 'b) t with sexp_of val create (** [growth_allowed] and [size] are both optionally passed on to the underlying call to [Hashtbl.create]. *) : ?growth_allowed : bool (** default is [true] *) -> ?size : int (** default is [128] *) -> 'a Hashtbl.Hashable.t -> ('a, 'b) t val mem : ('a, _) t -> 'a -> bool val find : ('a, 'b) t -> 'a -> 'b Heap_block.t option val find_or_add : ('a, 'b) t -> 'a -> default:(unit -> 'b Heap_block.t) -> 'b Heap_block.t val remove : ('a, 'b) t -> 'a -> unit val add_exn : ('a, 'b) t -> key:'a -> data:'b Heap_block.t -> unit val replace : ('a, 'b) t -> key:'a -> data:'b Heap_block.t -> unit (** [key_is_using_space t key] returns [true] if [key] is using some space in [t]. [mem t key] implies [key_is_using_space t key], but it is also possible that that [key_is_using_space t key && not (mem t key)]. *) val key_is_using_space : ('a, _) t -> 'a -> bool (** [reclaim_space_for_keys_with_unused_data t] reclaims space for all keys in [t] whose data has been detected (by a finalizer) to be unused. Only [key]s such that [key_is_using_space t key && not (mem t key)] will be reclaimed. *) val reclaim_space_for_keys_with_unused_data : (_, _) t -> unit (** [set_run_when_unused_data t ~thread_safe_f] calls [thread_safe_f] in the finalizer attached to each [data] in [t], after ensuring the entry being finalized will be handled in the next call to [reclaim_space_for_keys_with_unused_data]. This can be used to arrange to call [reclaim_space_for_keys_with_unused_data] at a convenient time in the future. [thread_safe_f] must be thread safe -- it is *not* safe for it to call any [Weak_hashtbl] functions. *) val set_run_when_unused_data : (_, _) t -> thread_safe_f:(unit -> unit) -> unit core-113.00.00/src/word_size.ml000066400000000000000000000000361256461075500161040ustar00rootroot00000000000000include Core_kernel.Word_size core-113.00.00/src/zone.ml000066400000000000000000000622261256461075500150630ustar00rootroot00000000000000(* Functions for parsing time zone database files (zic files). A time zone file consists (conceptually - the representation is more compact) of an ordered list of (float * [local_time_type]) that mark the boundaries (marked from the epoch) at which various time adjustment regimes are in effect. This can also be thought of as breaking down all time past the epoch into ranges with a [local_time_type] that describes the offset from GMT to apply to each range to get local time. *) open Core_kernel.Std module Sys = Core_sys let likely_machine_zones = ref [ "America/New_York"; "Europe/London"; "Asia/Hong_Kong"; "America/Chicago" ] exception Unknown_zone of string with sexp exception Invalid_file_format of string with sexp module Stable = struct module V1 = struct module Digest = struct include Digest include Binable.Of_binable (String) (struct let to_binable str = str let of_binable str = str type t = string end) let sexp_of_t t = Sexp.Atom (Digest.to_hex t) end module Regime = struct type t = { utc_off : float; is_dst : bool; abbrv : string; } with sexp_of, bin_io end (* holds information about when leap seconds should be applied - unused because we are translating based on a epoch system clock (see the .mli). *) module Leap_second = struct type t = { time : float; seconds : float; } with sexp_of, bin_io end module Transition = struct type t = { start_time : float; new_regime : Regime.t } with sexp_of, bin_io end (* IF THIS REPRESENTATION EVER CHANGES (particularly [name]), ENSURE THAT EITHER (1) all values serialize the same way in both representations, or (2) you add a new Time.Zone version to stable.ml Note that serialization is basically exclusively via the [name] field, and we do not ultimately export the [sexp_of_t] that [with sexp_of] generates. *) type strict = { name : string; file_info : (Digest.t * int64) option; transitions : Transition.t array; (* caches the index of the last transition we used to make lookups faster *) mutable last_regime_index : int; default_local_time_type : Regime.t; leap_seconds : Leap_second.t list; } with sexp_of (* Lazy.t serialises identically to the underlying type *) type t = strict Lazy.t with sexp_of let digest (lazy zone) = Option.map zone.file_info ~f:fst let file_size (lazy zone) = Option.map zone.file_info ~f:snd module Zone_file : sig val input_tz_file : zonename:string -> filename:string -> t end = struct let bool_of_int i = i <> 0 let input_long_as_float ic = let int32_of_char chr = Int32.of_int_exn (int_of_char chr) in let long = String.create 4 in really_input ic long 0 4; let sb1 = Int32.shift_left (int32_of_char long.[0]) 24 in let sb2 = Int32.shift_left (int32_of_char long.[1]) 16 in let sb3 = Int32.shift_left (int32_of_char long.[2]) 8 in let sb4 = int32_of_char long.[3] in let result = (Int32.bit_or (Int32.bit_or sb1 sb2) (Int32.bit_or sb3 sb4)) in Int32.to_float result ;; let input_long_long_as_float ic = let int63_of_char chr = Int63.of_int_exn (int_of_char chr) in let shift c bits = Int63.shift_left (int63_of_char c) bits in let long_long = String.create 8 in really_input ic long_long 0 8; let result = shift long_long.[0] 56 in let result = Int63.bit_or result (shift long_long.[1] 48) in let result = Int63.bit_or result (shift long_long.[2] 40) in let result = Int63.bit_or result (shift long_long.[3] 32) in let result = Int63.bit_or result (shift long_long.[4] 24) in let result = Int63.bit_or result (shift long_long.[5] 16) in let result = Int63.bit_or result (shift long_long.[6] 8) in let result = Int63.bit_or result (int63_of_char long_long.[7]) in Int63.to_float result ;; let input_long_as_int ic = let f = input_long_as_float ic in if f > Float.of_int Int.max_value then raise (Invalid_file_format "read int that cannot be represented as an \ OCaml native int"); Float.to_int f ;; let input_list ic ~len ~f = let rec loop c lst = if c > 0 then loop (c - 1) ((f ic) :: lst) else List.rev lst in loop len [] ;; let input_array ic ~len ~f = Array.of_list (input_list ic ~len ~f) let input_regime ic = let utc_off = input_long_as_float ic in let is_dst = bool_of_int (input_byte ic) in let abbrv_index = input_byte ic in let lt abbrv = { Regime. utc_off = utc_off; is_dst = is_dst; abbrv = abbrv; } in (lt,abbrv_index) ;; let input_abbreviations ic ~len = let raw_abbrvs = input_list ic ~len ~f:(input_char) in let buf = Buffer.create len in let _,indexed_abbrvs = List.fold raw_abbrvs ~init:(0, Map.Poly.empty) ~f:(fun (index,abbrvs) c -> match c with | '\000' -> let data = Buffer.contents buf in let next_index = index + (String.length data) + 1 in let abbrvs = Map.add abbrvs ~key:index ~data in Buffer.clear buf; (next_index,abbrvs) | c -> Buffer.add_char buf c; (index,abbrvs) ) in if Buffer.length buf <> 0 then raise (Invalid_file_format "missing \000 terminating character in input_abbreviations"); indexed_abbrvs ;; let input_tz_file_gen ~input_transition ~input_leap_second ic = let utc_local_count = input_long_as_int ic in let std_wall_count = input_long_as_int ic in let leap_count = input_long_as_int ic in let transition_count = input_long_as_int ic in let type_count = input_long_as_int ic in let abbrv_char_count = input_long_as_int ic in let transition_times = input_list ic ~f:input_transition ~len:transition_count in let transition_indices = input_list ic ~f:input_byte ~len:transition_count in let regimes = input_list ic ~f:input_regime ~len:type_count in let abbreviations = input_abbreviations ic ~len:abbrv_char_count in let leap_seconds = input_list ic ~f:input_leap_second ~len:leap_count in (* The following two arrays indicate two boolean values per regime that represent a three-value type that would translate to: type transition_type = UTC | Standard | Wall_clock However, these are only used by the system library when handling the case where the TZ variable is set, not to a time zone name, but instead is of the form: TZ = "std offset dst offset, rule" Which is deeply obscure, and almost certainly a mistake to use. This library makes no pretense about handling this case. We continue to read them in for completeness, and because it's possible that we will later discover a case where they are used. *) let _std_wall_indicators = input_array ic ~len:std_wall_count ~f:(fun ic -> bool_of_int (input_byte ic)) in let _utc_local_indicators = input_array ic ~len:utc_local_count ~f:(fun ic -> bool_of_int (input_byte ic)) in let regimes = Array.of_list (List.map regimes ~f:(fun (lt,abbrv_index) -> let abbrv = Map.find_exn abbreviations abbrv_index in lt abbrv )) in let raw_transitions = List.map2_exn transition_times transition_indices ~f:(fun time index -> let regime = regimes.(index) in (time, regime)) in let transitions = let rec make_transitions acc l = match l with | [] -> Array.of_list (List.rev acc) | (start_time,regime) :: rest -> make_transitions ({Transition. start_time = start_time; new_regime = regime } :: acc) rest in make_transitions [] raw_transitions in let default_local_time_type = match Array.find regimes ~f:(fun r -> not r.Regime.is_dst) with | None -> regimes.(0) | Some ltt -> ltt in (fun name file_info -> { name = name; file_info = Some file_info; transitions = transitions; last_regime_index = 0; default_local_time_type = default_local_time_type; leap_seconds = leap_seconds; } ) ;; let input_leap_second_gen ~input_leap_second ic = let leap_time = input_leap_second ic in let seconds = input_long_as_float ic in { Leap_second. time = leap_time; seconds = seconds; } ;; let read_header ic = let buf = String.create 4 in really_input ic buf 0 4; if buf <> "TZif" then raise (Invalid_file_format "magic characters TZif not present"); let version = match input_char ic with | '\000' -> `V1 | '2' -> `V2 | bad_version -> raise (Invalid_file_format (sprintf "version (%c) is invalid" bad_version)) in (* space reserved for future use in the format *) really_input ic (String.create 15) 0 15; version ;; let input_tz_file_v1 ic = let input_leap_second = input_leap_second_gen ~input_leap_second:input_long_as_float in input_tz_file_gen ~input_transition:input_long_as_float ~input_leap_second ic ;; (* version 2 timezone files have the format: part 1 - exactly the same as v1 part 2 - same format as v1, except that 8 bytes are used to store transition times and leap seconds part 3 - a newline-encloded, POSIX-TZ-environment-variable-style string for use in handling instants after the last transition time stored in the file (with nothing between the newlines if there is no POSIX representation for such instants) We handle files in this format by parsing the first part exactly as a v1 timezone file and then continuing to parse with 64bit reading functions in the right places. *) let input_tz_file_v2 ic = let _ = input_tz_file_v1 ic in (* the header is fully repeated *) assert (read_header ic = `V2); let input_leap_second = input_leap_second_gen ~input_leap_second:input_long_long_as_float in input_tz_file_gen ~input_transition:input_long_long_as_float ~input_leap_second ic ;; let input_tz_file ~zonename ~filename = try protectx (In_channel.create filename) ~finally:In_channel.close ~f:(fun ic -> let make_zone = match read_header ic with | `V1 -> input_tz_file_v1 ic | `V2 -> input_tz_file_v2 ic in let file_digest = Digest.file filename in let file_size = (Core_unix.stat filename).Core_unix.st_size in let r = make_zone zonename (file_digest, file_size) in lazy r) with | Invalid_file_format reason -> raise (Invalid_file_format (sprintf "%s - %s" filename reason)) ;; end module Zone_cache : sig val initialized_zones : unit -> (string * t) list val fill : unit -> unit val find_or_load : string -> t option val find_or_load_matching : t -> t option end = struct type z = { mutable full : bool; basedir : string; table : t String.Table.t } let the_one_and_only = { full = false; basedir = Option.value (Sys.getenv "TZDIR") ~default:"/usr/share/zoneinfo/"; table = String.Table.create (); } ;; let find zone = Hashtbl.find the_one_and_only.table zone let find_or_load zonename = match find zonename with | Some z -> Some z | None -> if the_one_and_only.full then None else begin try let filename = the_one_and_only.basedir ^ "/" ^ zonename in let zone = Zone_file.input_tz_file ~zonename ~filename in Hashtbl.set the_one_and_only.table ~key:zonename ~data:zone; Some zone with | _ -> None end ;; let traverse basedir ~f = let skip_prefixes = [ "Etc/GMT"; "right/"; "posix/"; ] in let maxdepth = 10 in let basedir_len = String.length basedir + 1 in let rec dfs dir depth = if depth < 1 then () else begin Array.iter (Sys.readdir dir) ~f:(fun fn -> let fn = dir ^ "/" ^ fn in let relative_fn = String.drop_prefix fn basedir_len in if Sys.is_directory fn = `Yes then begin if not (List.exists skip_prefixes ~f:(fun prefix -> String.is_prefix ~prefix relative_fn)) then dfs fn (depth - 1) end else f relative_fn ) end in dfs basedir maxdepth ;; let fill () = if not the_one_and_only.full then begin traverse the_one_and_only.basedir ~f:(fun zone_name -> ignore (find_or_load zone_name)); the_one_and_only.full <- true; end ;; TEST = fill (); let result = Option.is_some (find "America/New_York") in (* keep this test from contaminating tests later in the file *) the_one_and_only.full <- false; Hashtbl.clear the_one_and_only.table; result ;; let to_alist () = Hashtbl.to_alist the_one_and_only.table let initialized_zones t = List.sort ~cmp:(fun a b -> String.ascending (fst a) (fst b)) (to_alist t) ;; let find_or_load_matching t1 = Core_kernel.With_return.with_return (fun r -> let return_if_matches zone_name = let filename = String.concat ~sep:"/" [the_one_and_only.basedir; zone_name] in let matches = try file_size t1 = Some (Core_unix.stat filename).Core_unix.st_size && digest t1 = Option.(join (map (find_or_load zone_name) ~f:digest)) with | _ -> false in if matches then r.Core_kernel.With_return.return (find_or_load zone_name) else (); in List.iter !likely_machine_zones ~f:return_if_matches; traverse the_one_and_only.basedir ~f:return_if_matches; None) ;; end let init () = Zone_cache.fill () let initialized_zones () = Zone_cache.initialized_zones () let of_utc_offset ~hours:offset = assert (offset >= -24 && offset <= 24); let name = if offset = 0 then "UTC" else sprintf "UTC%s%d" (if offset < 0 then "-" else "+") (abs offset) in lazy { name = name; file_info = None; transitions = [||]; last_regime_index = 0; default_local_time_type = {Regime. utc_off = Float.of_int (offset * 60 * 60); is_dst = false; abbrv = name; }; leap_seconds = [] } ;; let default_utc_offset_deprecated (lazy t) = let ltt = t.default_local_time_type in Int.of_float ltt.Regime.utc_off ;; let find zone = let zone = (* The offices should be considered legacy/deprecated aliases. Other aliases are for convenience. *) match zone with | "utc" -> "UTC" | "gmt" -> "GMT" (* legacy *) | "chi" -> "America/Chicago" | "nyc" -> "America/New_York" | "hkg" -> "Asia/Hong_Kong" | "lon" | "ldn" -> "Europe/London" | "tyo" -> "Asia/Tokyo" (* catchall *) | _ -> zone in Zone_cache.find_or_load zone ;; let find_exn zone = match find zone with | None -> raise (Unknown_zone zone) | Some z -> z ;; let local = lazy (Lazy.force begin match Sys.getenv "TZ" with | Some zone_name -> find_exn zone_name | None -> let localtime_t = Zone_file.input_tz_file ~zonename:"/etc/localtime" ~filename:"/etc/localtime" in match Zone_cache.find_or_load_matching localtime_t with | Some t -> t | None -> localtime_t end) ;; let t_of_sexp sexp = match sexp with | Sexp.Atom "Local" -> local | Sexp.Atom name -> begin try (* This special handling is needed because the offset directionality of the zone files in /usr/share/zoneinfo for GMT files is the reverse of what is generally expected. That is, GMT+5 is what most people would call GMT-5. *) if String.is_prefix name ~prefix:"GMT-" || String.is_prefix name ~prefix:"GMT+" || String.is_prefix name ~prefix:"UTC-" || String.is_prefix name ~prefix:"UTC+" || name = "GMT" || name = "UTC" then begin let offset = if name = "GMT" || name = "UTC" then 0 else let base = Int.of_string (String.sub name ~pos:4 ~len:(String.length name - 4)) in match name.[3] with | '-' -> (-1) * base | '+' -> base | _ -> assert false in of_utc_offset ~hours:offset end else find_exn name with exc -> of_sexp_error (sprintf "Time.Zone.t_of_sexp: %s" (Exn.to_string exc)) sexp end | _ -> of_sexp_error "Time.Zone.t_of_sexp: expected atom" sexp ;; let sexp_of_t (lazy t) = if t.name = "/etc/localtime" then failwith "the local time zone cannot be serialized"; Sexp.Atom t.name ;; include Sexpable.To_stringable (struct type nonrec t = t with sexp end) let compare t1 t2 = String.compare (to_string t1) (to_string t2) include (Binable.Of_binable (String) (struct type nonrec t = t let to_binable (lazy t) = if t.name = "/etc/localtime" then failwith "the local time zone cannot be serialized"; t.name let of_binable s = t_of_sexp (Sexp.Atom s) end) : Binable.S with type t := t) end TEST_MODULE "Zone.V1" = Core_kernel.Stable_unit_test.Make (struct include V1 let equal (lazy z1) (lazy z2) = z1.name = z2.name let tests = let zone = find_exn in [ zone "nyc", "America/New_York", "\016America/New_York"; zone "ldn", "Europe/London", "\013Europe/London"; zone "hkg", "Asia/Hong_Kong", "\014Asia/Hong_Kong"; ] ;; TEST_UNIT "special form [Local]" = ignore (t_of_sexp (Sexp.of_string "Local")) ;; end) end include Stable.V1 let utc = of_utc_offset ~hours:0 let clock_shift_at zone i = let previous_shift = if i = 0 then zone.default_local_time_type.utc_off else zone.transitions.(i - 1).new_regime.utc_off in ( Time_internal.T.of_float zone.transitions.(i).start_time , Span.of_float (zone.transitions.(i).new_regime.utc_off -. previous_shift) ) let next_clock_shift (lazy zone) ~after = let segment_of (transition : Transition.t) = if Time_internal.T.(of_float transition.start_time > after) then `Right else `Left in Option.map (Array.binary_search_segmented zone.transitions ~segment_of `First_on_right) ~f:(fun i -> clock_shift_at zone i) ;; let prev_clock_shift (lazy zone) ~before = let segment_of (transition : Transition.t) = if Time_internal.T.(of_float transition.start_time < before) then `Left else `Right in Option.map (Array.binary_search_segmented zone.transitions ~segment_of `Last_on_left) ~f:(fun i -> clock_shift_at zone i) ;; TEST_MODULE "next_clock_shift, prev_clock_shift" = struct let mkt ?(year=2013) month day hr min = let ofday_mins = ((Float.of_int hr *. 60.) +. (Float.of_int min)) in let ofday_sec = ofday_mins *. 60. in Time_internal.T.of_float (Time_internal.utc_mktime ~year ~month ~day ~ofday_sec) TEST "UTC" = Option.is_none (next_clock_shift utc ~after:(mkt 01 01 12 00)) && Option.is_none (prev_clock_shift utc ~before:(mkt 01 01 12 00)) module Time_as_float = struct type t = Time_internal.T.t with compare let sexp_of_t t = Float.sexp_of_t (Time_internal.T.to_float t) end let expect_next after next = <:test_result< (Time_as_float.t * Span.t) option >> ~expect:(Some next) (next_clock_shift (find_exn "Europe/London") ~after) let expect_prev before prev = <:test_result< (Time_as_float.t * Span.t) option >> ~expect:(Some prev) (prev_clock_shift (find_exn "Europe/London") ~before) let expect_between time prev next = expect_prev time prev; expect_next time next let bst_start = mkt ~year:2013 03 31 01 00, Span.hour let bst_end = mkt ~year:2013 10 27 01 00, Span.(neg hour) let bst_start_2014 = mkt ~year:2014 03 30 01 00, Span.hour TEST_UNIT "outside BST" = expect_next (mkt 01 01 12 00) bst_start TEST_UNIT "just before BST start" = expect_next (mkt 03 31 00 59) bst_start TEST_UNIT "on BST start time" = expect_next (mkt 03 31 01 00) bst_end TEST_UNIT "just after BST start" = expect_between (mkt 03 31 01 01) bst_start bst_end TEST_UNIT "inside BST" = expect_between (mkt 06 01 12 00) bst_start bst_end TEST_UNIT "just before BST end" = expect_between (mkt 10 27 00 59) bst_start bst_end TEST_UNIT "BST end time" = expect_between (mkt 10 27 01 00) bst_start bst_start_2014 TEST_UNIT "just after BST end" = expect_between (mkt 10 27 01 01) bst_end bst_start_2014 end let convert_transition (transition : Transition.t) transtype = match transtype with | `UTC -> transition.start_time | `Local -> transition.start_time +. transition.new_regime.utc_off ;; (* Determine if [time] is governed by the regime in [transitions.(index)]. *) let in_transition transitions ~index time transtype = try let s = convert_transition transitions.(index) transtype in let e = convert_transition transitions.(index + 1) transtype in s <= time && time < e with | _ -> false ;; (* [find_local_regime zone `UTC time] finds the local time regime in force in [zone] at [seconds], from 1970/01/01:00:00:00 UTC. [find_local_regime zone `Local seconds] finds the local time regime in force in [zone] at [seconds], from 1970/01/01:00:00:00 of [zone]. *) let find_local_regime (lazy zone) transtype time = let module T = Transition in let transitions = zone.transitions in let num_transitions = Array.length transitions in if num_transitions = 0 then zone.default_local_time_type else if transitions.(0).T.start_time > time then zone.default_local_time_type else begin if in_transition transitions ~index:zone.last_regime_index time transtype then transitions.(zone.last_regime_index).new_regime else begin let segment_of (transition : Transition.t) = let start_time = convert_transition transition transtype in if time >= start_time then `Left else `Right in let index = Option.value_exn (Array.binary_search_segmented transitions ~segment_of `Last_on_left) in zone.last_regime_index <- index; transitions.(index).new_regime end end ;; let shift_epoch_time zone repr_type epoch = let r = find_local_regime zone repr_type epoch in match repr_type with | `Local -> epoch -. r.Regime.utc_off | `UTC -> epoch +. r.Regime.utc_off ;; let abbreviation zone time = (find_local_regime zone `UTC time).Regime.abbrv ;; let name (lazy zone) = zone.name include Identifiable.Make (struct let module_name = "Core.Std.Time.Zone" include Stable.V1 let of_string = of_string let to_string = to_string (* The correctness of these relies on not exposing raw loading/creation functions to the outside world that would allow the construction of two Zone's with the same name and different transitions. *) let hash t = String.hash (to_string t) end) core-113.00.00/src/zone.mli000066400000000000000000000327361256461075500152370ustar00rootroot00000000000000(** Time-zone handling. *) open Core_kernel.Std (** {1 User-friendly interface} *) (** The type of a time-zone. bin_io and sexp representations of Zone.t are the name of the zone, and not the full data that is read from disk when Zone.find is called. The full Zone.t is reconstructed on the receiving/reading side by reloading the zone file from disk. Any zone name that is accepted by [find] is acceptable in the bin_io and sexp representations. *) type t include Identifiable.S with type t := t (** [find name] looks up a [t] by its name and returns it. *) val find : string -> t option val find_exn : string -> t (** [local] is the machine's local timezone, as determined from the [TZ] environment variable or the [/etc/localtime] file. It is computed from the state of the process environment and on-disk tzdata database at some unspecified moment prior to its first use, so its value may be unpredictable if that state changes during program operation. Arguably, changing the timezone of a running program is a problematic operation anyway -- most people write code assuming the clock doesn't suddenly jump several hours without warning. Note that any function using this timezone can throw an exception if the [TZ] environment variable is misconfigured or if the appropriate timezone files can't be found because of the way the box is configured. We don't sprinkle [_exn] all over all the names in this module because such misconfiguration is quite rare. *) val local : t (** [likely_machine_zones] is a list of zone names that will be searched first when trying to determine the machine zone of a box. Setting this to a likely set of zones for your application will speed the very first use of the local timezone. *) val likely_machine_zones : string list ref (** [of_utc_offset offset] returns a timezone with a static UTC offset (given in hours). *) val of_utc_offset : hours:int -> t (** [default_utc_offset] returns the UTC offset of default regime for timezone [t] in seconds. Note: the default utc offset may not reflect the current utc offset. *) val default_utc_offset_deprecated : t -> int (** [utc] the UTC time zone. Included for convenience *) val utc : t (** [abbreviation zone t] returns t abbreviation name such as EDT, EST, JST of given [zone] at the time [t]. This string conversion is one-way only, and cannot reliably be turned back into a t *) val abbreviation : t -> float -> string (** [name zone] returns the name of the time zone *) val name : t -> string (* {1 Low-level functions} The functions below are lower level and should be used more rarely. *) (** [init ()] pre-load all available time zones from disk, this function has no effect if it is called multiple times. Time zones will otherwise be loaded at need from the disk on the first call to find/find_exn. *) val init : unit -> unit (** [digest t] return the MD5 digest of the file the t was created from (if any) *) val digest : t -> string option (** [initialized_zones ()] returns a sorted list of time zone names that have been loaded from disk thus far. *) val initialized_zones : unit -> (string * t) list (** [shift_epoch_time zone [`Local | `UTC] time] Takes an epoch (aka "unix") time given either in local or in UTC (as indicated in the arguments) and shifts it according to the local time regime in force in zone. That is, given a Local epoch time it will return the corresponding UTC timestamp and vice versa. This function is low level, and is not intended to be called by most client code. Use the high level functions provided in Time instead. *) val shift_epoch_time : t -> [`Local | `UTC] -> float -> float (** Takes a [Time.t] and returns the next [Time.t] strictly after it, if any, that the time zone UTC offset changes, and by how much it does so. *) val next_clock_shift : t -> after:Time_internal.T.t -> (Time_internal.T.t * Span.t) option (** As [next_clock_shift], but strictly *before* the given time. *) val prev_clock_shift : t -> before:Time_internal.T.t -> (Time_internal.T.t * Span.t) option exception Unknown_zone of string exception Invalid_file_format of string module Stable : sig module V1 : sig type nonrec t = t with bin_io, compare, sexp end end (** {1 Notes on time} This library replicates and extends the functionality of the standard Unix time handling functions (currently exposed in the Unix module, and indirectly through the Time module). Things you should know before delving into the mess of time... {2 Some general resources (summarized information also appears below) } {v general overview - http://www.twinsun.com/tz/tz-link.htm zone abbreviations - http://blogs.msdn.com/oldnewthing/archive/2008/03/07/8080060.aspx leap seconds - http://en.wikipedia.org/wiki/Leap_second epoch time - http://en.wikipedia.org/wiki/Unix_time UTC/GMT time - http://www.apparent-wind.com/gmt-explained.html TAI time - http://en.wikipedia.org/wiki/International_Atomic_Time Almost every possible time measurement - http://www.ucolick.org/~sla/leapsecs/timescales.html v} {2 Standards for measuring time } - Epoch time/Unix time/Posix time: Defined as the number of seconds that have passed since midnight, January 1st, 1970 GMT. However, under epoch time, a day is always 86,400 seconds long, and a minute never contains more than 60 total seconds. In other words, epoch time does not take leap seconds into account properly. What a POSIX compliant system does during a leap second depends on the way in which its clock is managed. It either ignores it, replays the second, or causes a second to last longer than a second (retards the second). The important thing to remember is that however the transition is managed, all days start on an evenly divisible multiple of 86,400. - GMT/Greenwich Mean Time/Greenwich Civil Time: The time based on the movement of the sun relative to the meridian through the Old Greenwich Observatory (0 degrees). The movement of the sun in this case is a "mean" movement of the sun to adjust for slight eccentricities in the rotation of the earth, as well as for the effect of the tilt of the earth on the visible speed of the sun across the sky at different times of the year. GMT is often used synonymously with the term UTC (see below), but may also be used to refer to the time system described here, which differs from UTC (as of 2009) by ~1 second. - Standard Time: The time based on the adjusted (as in GMT) movement of the sun over a point on the earth that is not Greenwich. Colloquially, the time in a time zone without accounting for any form of daylight savings time. - Wall Clock Time: The time as it appears on a clock on the wall in a given time zone. Essentially this is standard time with DST adjustments. - TAI: International atomic time. The time based on a weighted average of the time kept by roughly 300 atomic clocks worldwide. TAI is written using the same format as normal solar (also called civil) times, but is not based on, or adjusted for the apparent solar time. Thus, as of 2009 TAI appears to be ahead of most other time systems by ~34 seconds when written out in date/time form (2004-09-17T00:00:32 TAI is 2004-09-17T00:00:00 UTC) - UTC/Universal Coordinated Time: Often taken as just another term for GMT, UTC is actually TAI adjusted with leap seconds to keep it in line with apparent solar time. Each UTC day is not an exact number of seconds long (unlike TAI or epoch time), and every second is exactly one real second long (unlike GMT, which is based entirely on the apparent motion of the sun, meaning that seconds under GMT slowly get longer as the earth's rotation slows down). Leap seconds are determined by the rotation of the earth, which is carefully measured by the International Earth Rotation Service in Paris, France using a combination of satellite and lunar laser ranging, very long baseline interferometry, and Navstar Global Positioning System (GPS) stations. This isn't important for using UTC, but is very cool. UTC is not well defined before about 1960. - Windows File Time: The number of 100-nanosecond intervals that have elapsed since 12:00 A.M. January 1, 1601, UTC. This is great because UTC has no meaning in 1601 (being based on atomic timekeeping technologies that didn't exist then), and also because 1601 predates the development of even reasonably accurate clocks of any sort. The reasoning behind the Windows epoch time choice is that "The Gregorian calendar operates on a 400-year cycle, and 1601 is the first year of the cycle that was active at the time Windows NT was being designed. In other words, it was chosen to make the math come out nicely." (http://blogs.msdn.com/oldnewthing/archive/2009/03/06/9461176.aspx) - VBScript (this is my favorite): http://blogs.msdn.com/ericlippert/archive/2003/09/16/eric-s-complete-guide-to-vt-date.aspx All of these systems start to exhibit problems as you go further back in time, partly because truly accurate timekeeping didn't make an appearance until roughly 1958, and partly because different parts of the world didn't actually have well defined time zones for a long time. If you go back far enough, you run into the switch between the Julian (old) and the Gregorian calendar, which happened at different times in history in different places in the world. {2 How does a system determine what time zone it is in? } + Check to see if the TZ environment variable is set. If it is, it can be set to one of three forms, two of which are rarely, if ever used see: http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html for more information on the obscure forms. The common form represents a relative path from the base /usr/share/zoneinfo/posix, and is generally in the form of a continent or country name paired with a city name (Europe/London, America/New_York). This is used to load the specified file from disk, which contains a time zone database in zic format (man tzfile). + If TZ is not set, the system will try to read the file located at /etc/localtime, which must be a zic timezone database (and which is often just a symlink into /usr/share/zoneinfo/posix). + If /etc/localtime cannot be found, then the system is assumed to be in GMT. It's worth noting that under this system there is no place on the system to go to get the name of the file you are using (/etc/localtime may not be a link, and may just be a copy, or its own database not represented in /usr/share/zoneinfo). Additionally, the names of the files in the system zoneinfo database follow an internal standard, and there is no established standard for naming timezones. So even if you were using one of these files, and you did know its name, you cannot assume that that name matches any timezone specified by any other system or description. One common misconception about time zones is that the standard time zone abbreviations can be used. For instance, EST surely refers to Eastern Standard Time. This is unfortunately not true - CST can refer to China Central Time, Central Standard Time, or Cuba Summer Time for instance - and time zone libraries that appear to correctly parse times that use time zone abbreviations do so by using a heuristic that usually assumes you mean a time in the US or Europe, in that order. Time zones also sometimes use two different abbreviations depending on whether the time in question is in standard time, or daylight savings time. These abbreviations are kept in the timezone databases, which is how programs like date manage to output meaningful abbreviations, it is only reading in times with abbreviations that is poorly specified. This library contains a function that attempts to make an accurate determination of the machine timezone by testing the md5 sum of the currently referenced timezone file against all of the possible candidates in the system database. It additionally makes some adjustments to return the more common timezone names since some files in the database are duplicated under several names. It returns an option because of the problems mentioned above. {2 The problems with string time conversions } There are two cases where string time conversions are problematic, both related to daylight savings time. In the case where time jumps forward one hour, there are possible representations of times that never happened 2006-04-02T02:30:00 in the eastern U.S. never happened for instance, because the clock jumped forward one hour directly from 2 to 3. Unix time zone libraries asked to convert one of these times will generally produce the epoch time that represents the time 1/2 hour after 2 am, which when converted back to a string representation will be T03:30:00. The second case is when the clocks are set back one hour, which causes one hour of time to happen twice. Converting a string in this range without further specification into an epoch time is indeterminate since it could be referring to either of two times. Unix libraries handle this by either allowing you to pass in a dst flag to the conversion function to specify which time you mean, or by using a heuristic to guess which time you meant. The existence of both cases make a strong argument for serializing all times in UTC, which doesn't suffer from these issues. *) core-113.00.00/test/000077500000000000000000000000001256461075500137365ustar00rootroot00000000000000core-113.00.00/test/avltree_test.ml000066400000000000000000000064451256461075500170020ustar00rootroot00000000000000module Avltree = Core_kernel.Avltree open OUnit open Core.Std let test_f t s test_data f = let is_present i = assert (Avltree.mem !t ~compare i); begin match Avltree.find !t ~compare i with | None -> assert false | Some j -> assert (i = j) end; in Avltree.invariant !t ~compare; Array.iter test_data ~f:(fun i -> t := f ~set:s ~t ~present:(Set.mem !s i) ~i; Avltree.invariant !t ~compare; Set.iter !s ~f:is_present; Avltree.iter !t ~f:(fun ~key ~data -> assert (Set.mem !s key && key = data)); Avltree.fold !t ~init:() ~f:(fun ~key ~data () -> assert (Set.mem !s key && key = data))) ;; let do_add ~set ~t ~present ~i ~added = (* Set added to be the opposite of the expected value, so we can verify that it in fact does get set and it is set to the right value (as opposed to the value being correct to start with, and we made no write to it.) *) added := present; let res = Avltree.add !t ~compare ~added ~key:i ~data:i in if present then assert (not !added) else assert (!added); set := Set.add !set i; res ;; let test_add t s test_data = let added = ref false in test_f t s test_data (fun ~set ~t ~present ~i -> do_add ~set ~t ~present ~i ~added) ;; let do_add_if_not_exists ~set ~t ~present ~i ~added = added := present; let res = Avltree.add !t ~replace:false ~compare ~added ~key:i ~data:(if present then i+1 else i) in if present then assert (not !added) else assert (!added); if not present then set := Set.add !set i; res ;; let test_add_if_not_exists t s test_data = let added = ref false in test_f t s test_data (fun ~set ~t ~present ~i -> do_add_if_not_exists ~set ~t ~present ~i ~added) ;; let do_remove ~set ~t ~present ~i ~removed = removed := not present; let res = Avltree.remove !t ~compare ~removed i in if present then assert (!removed) else assert (not !removed); set := Set.remove !set i; res ;; let test_remove t s test_data = let removed = ref false in test_f t s test_data (fun ~set ~t ~present ~i -> do_remove ~set ~t ~present ~i ~removed) ;; let test_add_remove t s test_data = let add = ref false in let r = ref false in test_f t s test_data (fun ~set ~t ~present ~i -> if !add then (add := false; do_add ~set ~t ~present ~i ~added:r) else (add := true; do_remove ~set ~t ~present ~i ~removed:r)) ;; let test name dset add_remove_dset = let t = ref Avltree.empty in let s = ref Set.Poly.empty in [ ("add_lookup_" ^ name) >:: (fun () -> test_add t s dset); ("add_if_not_exists_lookup_" ^ name) >:: (fun () -> test_add_if_not_exists t s dset); ("add_remove_lookup_" ^ name) >:: (fun () -> test_add_remove t s add_remove_dset); ("remove_lookup_" ^ name) >:: (fun () -> test_remove t s dset) ] ;; let test = let size = 1000 in let (random_data1, random_data2) = let s = Random.State.make_self_init () in Array.init size ~f:(fun _ -> Random.State.int s 10000), Array.init size ~f:(fun _ -> Random.State.int s 10000) in let sorted_data = Array.init size ~f:ident in let reverse_sorted_data = let x = Array.copy sorted_data in Array.rev_inplace x; x in "Avltree" >::: (test "random" random_data1 random_data2 @ test "sorted" sorted_data random_data2 @ test "reverse_sorted" reverse_sorted_data random_data2) ;; core-113.00.00/test/backtrace_manual_test.ml000066400000000000000000000003071256461075500206030ustar00rootroot00000000000000open Core.Std let f n = if n = 2 then ( Printf.eprintf "%s%!" (Backtrace.to_string (Backtrace.get ())) ) else Printf.printf "foo\n%!" let g () = List.iter [1; 2; 3] ~f let () = g () core-113.00.00/test/bag_test.ml000066400000000000000000000045021256461075500160610ustar00rootroot00000000000000open OUnit;; open Core.Std let test = "bag" >::: [ "foo" >:: (fun () -> "create" @? begin let b = Bag.create () in Bag.invariant b; assert (Bag.is_empty b); assert (0 = Bag.length b); true; end; "add1" @? begin let b = Bag.create () in let _e1 = Bag.add b 1 in Bag.invariant b; assert (1 = Bag.length b); assert (not (Bag.is_empty b)); true; end; "add2" @? begin let b = Bag.create () in let _e1 = Bag.add b 1 in let _e2 = Bag.add b 2 in Bag.invariant b; assert (2 = Bag.length b); assert (not (Bag.is_empty b)); true end; "remove" @? begin let b = Bag.create () in ignore (Bag.remove b (Bag.add b 1)); Bag.invariant b; assert (Bag.is_empty b); true; end; "remove2" @? begin let b = Bag.create () in let e1 = Bag.add b 1 in let _e2 = Bag.add b 2 in ignore (Bag.remove b e1); Bag.invariant b; assert (1 = Bag.length b); true; end; "add100" @? begin let b = Bag.create () in let n = 20 in for i = 1 to n do let _e = Bag.add b i in Bag.invariant b; done; assert (Bag.length b = n); for _i = 1 to n do Bag.invariant b; match Bag.remove_one b with | None -> assert false | Some _ -> () done; assert (Bag.is_empty b); Bag.invariant b; true end; "container" @? begin let b = Bag.create () in let n = 20 in for i = 1 to n do ignore (Bag.add b i); done; assert (n = Bag.fold b ~init:0 ~f:(fun n _ -> n + 1)); for i = 1 to n do assert (Bag.exists b ~f:(fun i' -> i = i')); done; Bag.iter b ~f:(fun i -> assert (1 <= i && i <= n)); assert (Bag.for_all b ~f:(fun i -> 1 <= i && i <= n)); true; end; ) ] core-113.00.00/test/bigbuffer_test.ml000066400000000000000000000021401256461075500172570ustar00rootroot00000000000000open Unix open OUnit;; open Core.Std open Bigstring_test let io_test ~n = fdpair_test ~n socketpair (fun buf fd -> let oc = out_channel_of_descr fd in Bigbuffer.output_buffer oc buf; flush oc) (fun ~n:_ orig_buf fd -> let ic = in_channel_of_descr fd in let buf = Bigbuffer.create 0 in Bigbuffer.add_channel buf ic (Bigbuffer.length orig_buf); "channel" @? (Bigbuffer.contents orig_buf = Bigbuffer.contents buf)) let test = "Bigbuffer" >::: [ "adding/extracting data" >:: (fun () -> let buf = Bigbuffer.create 100 in Bigbuffer.add_char buf 'x'; Bigbuffer.add_char buf 'y'; Bigbuffer.add_string buf "asdf"; Bigbuffer.add_substring buf "fdsa" 1 2; Bigbuffer.add_buffer buf buf; let str = "xyasdfds" in "contents" @? (Bigbuffer.contents buf = str ^ str); "big_contents" @? (Bigstring.to_string (Bigbuffer.big_contents buf) = str ^ str ); "sub" @? (Bigbuffer.sub buf ~pos:5 ~len:5 = "fdsxy"); io_test ~n:"" buf ); ] core-113.00.00/test/bigstring_test.ml000066400000000000000000000205421256461075500173220ustar00rootroot00000000000000open Core.Std;; open OUnit;; open Quickcheck_deprecated;; (***************************************************************************) (** Simple bigstring testing utilties *) (** bigstring generator *) let bsg ?(size=nng) ?(char=cg) () = let len = size () in let bs = Bigstring.create len in for i = 0 to len - 1 do bs.{i} <- char () done; bs ;; let png () = nng () + 1 let bs_of_s = Bigstring.of_string (** function for getting a short representation of a bigstring *) let repr bs = if Bigstring.length bs > 30 then let s = String.create 30 in Bigstring.To_string.blito ~src:bs ~src_len:30 ~dst:s (); sprintf "" (Bigstring.length bs) s else sprintf "" (Bigstring.to_string bs) ;; (***************************************************************************) (** suport code for individual tests *) let blit_test ~n ~src_pos ~dst_pos ~len (s1,s2) = let s1_orig = s1 and s2_orig = s2 in let s1 = String.copy s1 and s2 = String.copy s2 in let s_result = try String.blit ~src_pos ~dst_pos ~len ~src:s1 ~dst:s2; `Success s2 with e -> `Failure (Exn.to_string e) in let bs_result = try let bs1 = Bigstring.of_string s1 in let bs2 = Bigstring.of_string s2 in Bigstring.blito ~src:bs1 ~src_pos ~src_len:len ~dst:bs2 ~dst_pos (); `Success (Bigstring.to_string bs2) with e -> `Failure (Exn.to_string e) in let prefix = sprintf "blit %s: %s,%s - " n s1_orig s2_orig in match s_result, bs_result with | `Success rval, `Success rval' -> (prefix ^ "success") @? (rval = rval') | `Success _, `Failure err -> assert_failure (prefix ^ "string worked, bigstring failed: " ^ err) | `Failure err, `Success _ -> assert_failure (prefix ^ "bigstring worked, string failed: " ^ err) | `Failure _, `Failure _ -> () ;; (** takes a string as an argument, and blits it back and forth to a newly created bigstring *) let simple_conversion_test ~n s = let len = String.length s in let bs = Bigstring.create len in Bigstring.From_string.blito ~src:s ~dst:bs (); let s' = String.create len in Bigstring.To_string.blito ~src:bs ~dst:s' (); (sprintf "%s: %s" n s) @? (s' = s) ;; let really_output outc bs = let pos = ref 0 in let len = Bigstring.length bs in while !pos < len do let bytes = Bigstring.output ~pos:!pos outc bs in pos := !pos + bytes done (** takes a bigstring, writes it to a file, then opens it as an inchannel and passes it to the test function *) let inchan_test ~n test orig = let (fname,outc) = Filename.open_temp_file "bigstring_test" ".txt" in protect ~f:(fun () -> really_output outc orig; Out_channel.close outc; let inc = open_in fname in test ~n orig inc) ~finally:(fun () -> Unix.unlink fname) ;; (** like inchan test, but it passes a file descriptor to the test function *) let fd_test ~n test s = inchan_test ~n (fun ~n orig inc -> test ~n orig (Unix.descr_of_in_channel inc)) s ;; let really_read_test ~n bs fd = let len = Bigstring.length bs in let bs' = Bigstring.create len in Bigstring.really_read fd ~pos:0 ~len bs'; (sprintf "%s: %s" n (repr bs)) @? (bs = bs') ;; let socketpair () = Unix.socketpair ~domain:Unix.PF_UNIX ~kind:Unix.SOCK_STREAM ~protocol:0 let fdpair_test ~n fdpair sender receiver bs = try let (read,write) = fdpair () in let sth = Thread.create (fun () -> try sender bs write with e -> eprintf "ERROR: %s" (Exn.to_string e)) () in receiver ~n bs read; Thread.join sth; Unix.close read; Unix.close write with e -> assert_failure (sprintf "%s: receive exception: %s" n (Exn.to_string e)) let write_read_test ~n fdpair bs = fdpair_test ~n fdpair (fun bs fd -> Bigstring.really_write fd bs; ) (fun ~n bs fd -> let bs' = Bigstring.create (Bigstring.length bs) in Bigstring.really_read fd bs'; (sprintf "send/recv %s: %s,%s" n (repr bs) (repr bs')) @? (bs = bs')) bs let output_input_test ?(runs = 2) ~n fdpair bs = let ic = ref stdin in let oc = ref stdout in fdpair_test ~n fdpair (fun bs fd -> if !oc = stdout then oc := Unix.out_channel_of_descr fd; for _i = 1 to runs do Bigstring.really_output !oc bs done; flush !oc ) (fun ~n bs fd -> if !ic = stdin then ic := Unix.in_channel_of_descr fd; let bs' = Bigstring.create (Bigstring.length bs) in for _i = 1 to runs do Bigstring.really_input !ic bs' done; (sprintf "output/input %s: %s,%s" n (repr bs) (repr bs')) @? (bs = bs')) bs let test = "bigstring" >::: ["simple conversion" >:: (fun () -> simple_conversion_test ~n:"empty" ""; simple_conversion_test ~n:"simple" "0123434aslekX"; simple_conversion_test ~n:"single" "1"; repeat 50 (simple_conversion_test ~n:"random") sg; ); "input" >:: (fun () -> fd_test really_read_test ~n:"single" (bs_of_s "X"); fd_test really_read_test ~n:"simple" (bs_of_s "normal length string"); repeat 100 (fd_test really_read_test ~n:"random") (bsg ~size:png); repeat 100 (fd_test really_read_test ~n:"random big") (bsg ~size:(fun () -> 100 * png ())); ); "destruction" >:: (fun () -> let n = 100 in let bstr = Bigstring.create n in bstr.{0} <- 'x'; "initial size" @? (Bigstring.length bstr = n); "initial access" @? (bstr.{0} = 'x'); Bigstring.unsafe_destroy bstr; "destroyed size" @? (Bigstring.length bstr = 0); "destroyed access" @? begin try ignore (bstr.{0} = 'x'); false with Invalid_argument "index out of bounds" -> true end; "double destroy" @? begin try Bigstring.unsafe_destroy bstr; false with Failure _ -> true end; ); "blit" >:: (fun () -> blit_test ~n:"empty" ~src_pos:0 ~dst_pos:0 ~len:0 ("",""); blit_test ~n:"simple" ~src_pos:0 ~dst_pos:0 ~len:5 ("01234"," "); blit_test ~n:"shortdst" ~src_pos:0 ~dst_pos:0 ~len:5 ("01234"," "); blit_test ~n:"shortsrc" ~src_pos:0 ~dst_pos:0 ~len:5 ("0234"," "); blit_test ~n:"middle" ~src_pos:5 ~dst_pos:0 ~len:5 ("1234554321"," "); repeat 5000 (fun (s1,s2,src_pos,dst_pos,len) -> blit_test ~n:"random" ~src_pos ~dst_pos ~len (s1,s2)) (fun () -> (sg (), sg(),nng (), nng (), nng ())) ); "really write/read pipe" >:: (fun () -> let write_read_test = write_read_test Unix.pipe in (* write_read_test ~n:"empty" (bs_of_s ""); *) write_read_test ~n:"simple" (bs_of_s "A simple short string"); repeat 500 (write_read_test ~n:"random") (bsg ~size:png); repeat 500 (write_read_test ~n:"random big") (bsg ~size:(fun () -> 100 * png ())); ); "really write/read socketpair" >:: (fun () -> let write_read_test = write_read_test socketpair in (* write_read_test ~n:"empty" (bs_of_s ""); *) write_read_test ~n:"simple" (bs_of_s "A simple short string"); repeat 500 (write_read_test ~n:"random") (bsg ~size:png); repeat 500 (write_read_test ~n:"random big") (bsg ~size:(fun () -> 100 * png ())); ); "output/input socketpair" >:: (fun () -> let output_input_test ?runs = output_input_test ?runs socketpair in (* output_input_test ~n:"empty" (bs_of_s ""); *) repeat 5000 (output_input_test ~runs:100 ~n:"simple") (fun () -> bs_of_s "A simple short string"); repeat 500 (output_input_test ~n:"random") (bsg ~size:png); repeat 500 (output_input_test ~n:"random big") (bsg ~size:(fun () -> 100 * png ())); ); "sub" >:: (fun () -> let original = Bigstring.of_string "catfish" in match Bigstring.to_string (Bigstring.subo ~pos:3 original) with | "fish" -> () | other -> failwithf "Expected fish, got: %s" other ()); "sub_shared" >:: (fun () -> let original = Bigstring.of_string "catfish" in match Bigstring.to_string (Bigstring.sub_shared ~pos:3 original) with | "fish" -> () | other -> failwithf "Expected fish, got: %s" other ()); ] core-113.00.00/test/binary_packing_test.ml000066400000000000000000000055671256461075500203240ustar00rootroot00000000000000open Core.Std open OUnit;; module B = Binary_packing let test byte_order = let inverses inc inc_inc pack unpack min max to_string () = let try_it i = let buf = String.create 100 in pack ~byte_order ~buf ~pos:0 i; let i' = unpack ~byte_order ~buf ~pos:0 in if i' <> i then failwith (Printf.sprintf "failed on input %s; returned %s" (to_string i) (to_string i')) in let rec f i inc_by = if i < max then begin try_it i; let i' = inc inc_by i in if i' > i then f (inc inc_by i) (inc_by + inc_inc) end in f min 1; try_it max in [ "Binary_packing.test" >:: (fun () -> let test () = try Binary_packing.test (); true with _ -> false in Quickcheck_deprecated.laws_exn "\"Runs without raising\"" 1 (Quickcheck_deprecated.always ()) test ); "[pack|unpack]_signed_8" >:: inverses (+) 0 (fun ~byte_order:_ ~buf ~pos i -> B.pack_signed_8 ~buf ~pos i) (fun ~byte_order:_ ~buf ~pos -> B.unpack_signed_8 ~buf ~pos) (-0x80) 0x7F string_of_int; "[pack|unpack]_signed_16" >:: inverses (+) 0 B.pack_signed_16 B.unpack_signed_16 (-0x8000) 0x7FFF string_of_int; "[pack|unpack]_signed_32" >:: inverses (fun n -> Int32.(+) (Int32.of_int_exn n)) 1 B.pack_signed_32 B.unpack_signed_32 (Int32.of_string "-0x80000000") (Int32.of_string "0x7FFFFFFF") Int32.to_string; "[pack|unpack]_signed_32_int" >:: (if Sys.word_size = 64 then inverses (+) 1 B.pack_signed_32_int B.unpack_signed_32_int (int_of_string "-0x80000000") (int_of_string "0x7FFFFFFF") string_of_int else (fun () -> ())); "[pack|unpack]_signed_64" >:: ( let buf = String.make 8 'a' in let test name to_string p u ns () = List.iter ns ~f:(fun n -> p ~byte_order ~buf ~pos:0 n; let n' = u ~byte_order ~buf ~pos:0 in if n <> n' then failwith (sprintf "%s = unpack_%s (pack_%s %s)" (to_string n') name name (to_string n))) in test "signed_64" Int64.to_string B.pack_signed_64 B.unpack_signed_64 [-0x8000_0000_0000_0000L; -0x789A_BCDE_F012_3456L; -0xFFL; Int64.minus_one; Int64.zero; Int64.one; 0x789A_BCDE_F012_3456L; 0x7FFF_FFFF_FFFF_FFFFL] ); "[pack|unpack]_float" >:: (fun () -> let test_float i = let buf = String.create 100 in B.pack_float ~byte_order ~buf ~pos:0 i; let i' = B.unpack_float ~byte_order ~buf ~pos:0 in i' = i in Quickcheck_deprecated.laws_exn "unpack_float (pack_float x) = x" 100 Quickcheck_deprecated.fg test_float ); ] let test = "binary_packing" >::: (test `Big_endian @ test `Little_endian) core-113.00.00/test/blang_test.ml000066400000000000000000000105151256461075500164140ustar00rootroot00000000000000open OUnit open Core.Std open Blang let to_string t = Sexp.to_string (Blang.sexp_of_t String.sexp_of_t t) let (===) b1 b2 = if b1 <> b2 then failwithf "%s <> %s" (to_string b1) (to_string b2) () let same_sexp b1 b2 = let s1 = to_string b1 and s2 = to_string b2 in if s1 <> s2 then failwithf "%s <> %s" s1 s2 () let test = "blang" >::: [ "simplification" >::: [ (**) "not1" >:: (fun () -> not_ true_ === false_); "not2" >:: (fun () -> not_ false_ === true_); (**) "and1" >:: (fun () -> and_ [] === true_); "and2" >:: (fun () -> and_ [true_] === true_); "and3" >:: (fun () -> and_ [true_; base "A"] === base "A"); "and4" >:: (fun () -> and_ [base "A"; true_] === base "A"); "and5" >:: (fun () -> and_ [base "A"; base "B"; true_] === and_ [base "A"; base "B"]); "and6" >:: (fun () -> and_ [base "A"; true_; base "B"] === and_ [base "A"; base "B"]); "and7" >:: (fun () -> and_ [true_; base "A"; base "B"] === and_ [base "A"; base "B"]); "and8" >:: (fun () -> and_ [false_] === false_); "and9" >:: (fun () -> and_ [false_; base "A"] === false_); "and10" >:: (fun () -> and_ [base "A"; false_] === false_); "and11" >:: (fun () -> and_ [base "A"; base "B"; false_] === false_); "and12" >:: (fun () -> and_ [base "A"; false_; base "B"] === false_); "and13" >:: (fun () -> and_ [false_; base "A"; base "B"] === false_); (**) "or1" >:: (fun () -> or_ [] === false_); "or2" >:: (fun () -> or_ [false_] === false_); "or3" >:: (fun () -> or_ [false_; base "A"] === base "A"); "or4" >:: (fun () -> or_ [base "A"; false_] === base "A"); "or5" >:: (fun () -> or_ [base "A"; base "B"; false_] === or_ [base "A"; base "B"]); "or6" >:: (fun () -> or_ [base "A"; false_; base "B"] === or_ [base "A"; base "B"]); "or7" >:: (fun () -> or_ [false_; base "A"; base "B"] === or_ [base "A"; base "B"]); "or8" >:: (fun () -> or_ [true_] === true_); "or9" >:: (fun () -> or_ [true_; base "A"] === true_); "or10" >:: (fun () -> or_ [base "A"; true_] === true_); "or11" >:: (fun () -> or_ [base "A"; base "B"; true_] === true_); "or12" >:: (fun () -> or_ [base "A"; true_; base "B"] === true_); "or13" >:: (fun () -> or_ [true_; base "A"; base "B"] === true_); (**) "if1" >:: (fun () -> if_ true_ (base "A") (base "B") === base "A"); "if2" >:: (fun () -> if_ false_ (base "A") (base "B") === base "B"); "if3" >:: (fun () -> if_ (base "A") true_ (base "B") === or_ [base "A"; base "B"]); "if4" >:: (fun () -> if_ (base "A") (base "B") false_ === and_ [base "A"; base "B"]); "if5" >:: (fun () -> if_ (base "A") (base "B") true_ === or_ [not_ (base "A"); base "B"]); "if6" >:: (fun () -> if_ (base "A") false_ (base "B") === and_ [not_ (base "A"); base "B"]); (**) "ifnot1" >:: (fun () -> if_ (not_ false_) (base "A") (base "B") === base "A"); "ifnot2" >:: (fun () -> if_ (not_ true_) (base "A") (base "B") === base "B"); ]; "flattening" >::: [ "and" >:: (fun () -> same_sexp (and_ [base "A"; and_ [base "B"; base "C"]]) (and_ [base "A"; base "B"; base "C"])); "or" >:: (fun () -> same_sexp (or_ [base "A"; or_ [base "B"; base "C"]]) (or_ [base "A"; base "B"; base "C"])); ]; "substitution" >::: [ "base" >:: (fun () -> bind (base "A") (fun x -> and_ [base x; base x]) === and_ [base "A"; base "A"]); "and" >:: (fun () -> bind (and_ [base "A"; base "B"]) (fun x -> or_ [base x; base x]) === and_ [or_ [base "A"; base "A"]; or_ [base "B"; base "B"]]); ]; "values" >:: (fun () -> let blang1 = and_ [ if_ (and_ []) (base "this") (base "that"); or_ [ if_ (not_ (and_ [])) (base "something") (base "other"); base "yet another thing"; ] ] in let values = Blang.values blang1 in if ["this"; "other"; "yet another thing"] <> values then failwithf "Got: %s" (String.concat ~sep:"," values) ()); ] core-113.00.00/test/command-tests/000077500000000000000000000000001256461075500165145ustar00rootroot00000000000000core-113.00.00/test/command-tests/README000066400000000000000000000004101256461075500173670ustar00rootroot00000000000000These tests use a modified version of Mercurial's test framework that we don't currently package with the open-source release. If you find yourself wanting to run these tests, contact opensource@janestreet.com and we'll work on making it more generally available. core-113.00.00/test/command-tests/demo_child.ml000066400000000000000000000017311256461075500211370ustar00rootroot00000000000000open Core.Std (* Ensure that programs querying [Command.shape] of this executable preserve the environment. *) let () = assert ("test" = Sys.getenv_exn "ENVVAR") type args = { date : Date.t; file : string option; num : int; bool : bool option; } with sexp_of let command = Command.basic' ~summary:"child part of Command.exec demo" ~readme:(fun () -> "readme text. readme text. readme text. readme text. readme text. readme\n\ text. readme text. readme text. readme text. readme text. readme text. readme\n\ text. readme text. readme text.") Command.Param.( flag "date" (required date) ~doc:"DATE a required date argument" @> flag "file" (optional file) ~doc:"FILE an optional file argument" @> anon ("NUM" %: int) @> anon (maybe ("BOOL" %: bool)) @> nil ) (fun date file num bool () -> printf !"Entering main: %{Sexp}\n" (sexp_of_args {date; file; num; bool}) ) let () = Command.run command core-113.00.00/test/command-tests/demo_full_flag.ml000066400000000000000000000014631256461075500220110ustar00rootroot00000000000000open Core.Std let command = Command.basic' ~summary:"Test full flag validation" ~readme:(Fn.const "Simple readme") Command.Param.( flag "-full-flag-required" ~full_flag_required:() ~aliases:["full-alias-required"] ~doc:" make sure if the full argument is not provided, command bails" no_arg @> flag "-full-flag-not-required" ~aliases:["full-alias-not-required"] ~doc:" make sure that prefix matches still work" no_arg @> nil ) (fun un_abbreviatable abbreviatable () -> if un_abbreviatable then print_endline "passed the un-abbreviatable flag"; if abbreviatable then print_endline "passed the abbreviatable flag"; print_endline "doing stuff here!" ) let () = Command.run command core-113.00.00/test/command-tests/demo_grandparent.ml000066400000000000000000000004511256461075500223570ustar00rootroot00000000000000open Core.Std let exec_parent = Command.exec ~summary:"this command is in another executable" ~path_to_exe:(`Relative_to_me "demo_parent.exe") () let command = Command.group ~summary:"grandparent part of Command.exec demo" [ ("parent", exec_parent) ] let () = Command.run command core-113.00.00/test/command-tests/demo_help.ml000066400000000000000000000034641256461075500210110ustar00rootroot00000000000000open Core.Std type pong = Foo | Bar | Baz | Baa_baa let pong_arg = Command.Spec.Arg_type.of_alist_exn [ ("foo", Foo); ("bar", Bar); ("baz", Baz); ("baa\\ baa", Baa_baa); ] let readme () = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et\n\ ante a nibh scelerisque ultrices. Fusce consectetur dictum ante quis\n\ commodo." let basic = Command.basic' ~summary:"this command does stuff here" ~readme Command.Param.( flag "-ping" no_arg ~doc:" make sure ping is doing the same stuff" @> flag "-pong" (optional pong_arg) ~doc:"NAME which pong should do the stuff" @> anon ("OXIDE" %: pong_arg) @> anon ("DIODE" %: pong_arg) @> anon (maybe ("path" %: file)) (* Note: "path" becomes "PATH" in help output *) @> nil ) (fun _ _ _ _ _ () -> print_endline "doing stuff here!") let command = Command.group ~preserve_subcommand_order:() ~summary:"this command does stuff" [ ("jab", basic); ("JIB", basic); (* Note: subcommand names are automatically lowercased *) ( "adverb" , Command.group ~summary:"this command does more stuff" ~readme [ ("drolly", basic); ("opposable", basic); ]); ( "with-body" , Command.group ~summary:"this command does more stuff" ~body:(fun ~path -> print_endline "BEGIN body code"; print_endline (" path = (" ^ String.concat ~sep:" " path ^ ")"); print_endline " (running this instead of reporting a missing subcommand)"; print_endline "END body code"; ) [ ("drolly", basic); ("opposable", basic); ]); ("ordered" , Command.group ~summary:"group with unsorted subcommands" ~preserve_subcommand_order:() [ ("zzz", basic); ("aaa", basic); ]); ] let () = Command.run command core-113.00.00/test/command-tests/demo_internals.ml000066400000000000000000000012361256461075500220530ustar00rootroot00000000000000open Core.Std let summary = "summary" let basic = Command.basic' ~summary Command.Param.( path @> help @> args @> flag "foo" (optional int) ~doc:"NUM flag value" @> anon (maybe ("BAR" %: int)) @> nil ) (fun path help args _foo _bar () -> printf !"path = %{sexp:string list}\n" path; printf !"args = %{sexp:string list}\n" args; printf !"help = \n%s" (Lazy.force help) ) let group name subcommands = (name, Command.group ~summary subcommands) let command = Command.group ~summary [ ("foo", basic); ("bar", Command.group ~summary [("baz", basic)]); ] let () = Command.run command core-113.00.00/test/command-tests/demo_no_arg_abort.ml000066400000000000000000000016071256461075500225120ustar00rootroot00000000000000open Core.Std let dump_readme () : never_returns = print_endline "This is the contents of README.txt."; exit 0 let dump_grammar () : never_returns = print_endline "This is the contents of GRAMMAR.txt."; exit 0 type args = { foo : int option; anon : int option; } with sexp_of let command = Command.basic' ~summary:"demonstrate the no_arg_abort flag type" Command.Param.( flag "-readme" (no_arg_abort ~exit:dump_readme) ~doc: " display README.txt and quit" @> flag "-grammar" (no_arg_abort ~exit:dump_grammar) ~doc: " display GRAMMAR.txt and quit" @> flag "-foo" (optional int) ~doc:"NUM numeric flag" @> anon (maybe ("NUM" %: int)) @> nil ) (fun () () foo anon () -> printf !"entering main with args: %{sexp:args}\n" {foo; anon}; print_endline "doing stuff ..."; ) let () = Command.run command core-113.00.00/test/command-tests/demo_one_or_more.ml000066400000000000000000000011421256461075500223530ustar00rootroot00000000000000open Core.Std let command = Command.basic' ~summary:"Command.Spec.{one_or_more,non_empty_sequence} demo" Command.Param.( flag "foo" (one_or_more string) ~doc:"X required listed flag" @> anon (non_empty_sequence ("Y" %: string)) @> nil ) (fun xs ys () -> let info name zs = let zs = fst zs :: snd zs in Info.create name zs <:sexp_of> in let info = Info.of_list [ info "xs" xs; info "ys" ys; ] in print_endline (Info.to_string_hum info) ) let () = Command.run command core-113.00.00/test/command-tests/demo_parent.ml000066400000000000000000000006701256461075500213460ustar00rootroot00000000000000open Core.Std (* Ensure that programs querying [Command.shape] of this executable preserve the environment. *) let () = assert ("test" = Sys.getenv_exn "ENVVAR") let exec_child = Command.exec ~summary:"this command is in another executable" ~path_to_exe:(`Relative_to_me "demo_child.exe") () let command = Command.group ~summary:"parent part of Command.exec demo" [ ("child", exec_child) ] let () = Command.run command core-113.00.00/test/command-tests/demo_sexp_load.ml000066400000000000000000000011331256461075500220260ustar00rootroot00000000000000open Core.Std type config = {foo : int; bar : string} with sexp let command = Command.basic' ~summary:"demonstrate sexp loading during command line parsing" Command.Param.( step ~f:(fun m file -> (* this is kind of a strange thing to do in [step], but imagine a case where we want to validate some argument against the contents of a config file. *) m (Sexp.load_sexp_conv_exn file config_of_sexp)) @@ anon ("CONFIG-FILE" %: file) @> nil ) (fun config () -> Sexp.output_hum stdout (sexp_of_config config)) let () = Command.run command core-113.00.00/test/command-tests/etc/000077500000000000000000000000001256461075500172675ustar00rootroot00000000000000core-113.00.00/test/command-tests/etc/malformed.sexp000066400000000000000000000000331256461075500221320ustar00rootroot00000000000000((foo 3) ; (bar hello) ) core-113.00.00/test/command-tests/expected-output/000077500000000000000000000000001256461075500216535ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe.stdout000066400000000000000000000000001256461075500246110ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_-1-command-output-help-sexp.stdout000066400000000000000000000000001256461075500317630ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_-help.stderr000066400000000000000000000000001256461075500256570ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_-help_adverb.stderr000066400000000000000000000000001256461075500272020ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_-help_help.stderr000066400000000000000000000000001256461075500266670ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_-help_jab.stderr000066400000000000000000000000001256461075500264730ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_-help_nested.stderr000066400000000000000000000000001256461075500272210ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_1-command-output-help-sexp.stderr000066400000000000000000000000001256461075500316670ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_1_2-command-output-help-sexp.stderr000066400000000000000000000000001256461075500321100ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb.stdout000066400000000000000000000000001256461075500261340ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_-help.stderr000066400000000000000000000000001256461075500272020ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_-help_help.stderr000066400000000000000000000000001256461075500302120ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_-help_nemeses.stderr000066400000000000000000000000001256461075500307210ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_help.stderr000066400000000000000000000000001256461075500271250ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_help_-help.stderr000066400000000000000000000000001256461075500302120ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_help_-recursive.stderr000066400000000000000000000000001256461075500312710ustar00rootroot00000000000000main.exe_adverb_help_-recursive_-expand-dots.stderr000066400000000000000000000000001256461075500335750ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputmain.exe_adverb_help_-recursive_-expand-dots_-flags.stderr000066400000000000000000000000001256461075500350260ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputcore-113.00.00/test/command-tests/expected-output/main.exe_adverb_help_-recursive_-flags.stderr000066400000000000000000000000001256461075500325220ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_help_help.stderr000066400000000000000000000000001256461075500301350ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_help_help_-recursive.stderr000066400000000000000000000000001256461075500323010ustar00rootroot00000000000000main.exe_adverb_help_help_-recursive_-expand-dots.stderr000066400000000000000000000000001256461075500346050ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputmain.exe_adverb_help_help_-recursive_-expand-dots_-flags.stderr000066400000000000000000000000001256461075500360360ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputcore-113.00.00/test/command-tests/expected-output/main.exe_adverb_help_help_-recursive_-flags.stderr000066400000000000000000000000001256461075500335320ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_help_nemeses.stderr000066400000000000000000000000001256461075500306440ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_adverb_help_nemeses_-recursive.stderr000066400000000000000000000000001256461075500330100ustar00rootroot00000000000000main.exe_adverb_help_nemeses_-recursive_-expand-dots.stderr000066400000000000000000000000001256461075500353140ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputmain.exe_adverb_help_nemeses_-recursive_-expand-dots_-flags.stderr000066400000000000000000000000001256461075500365450ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputmain.exe_adverb_help_nemeses_-recursive_-flags.stderr000066400000000000000000000000001256461075500341620ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputcore-113.00.00/test/command-tests/expected-output/main.exe_adverb_nemeses_-help.stderr000066400000000000000000000000001256461075500307210ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help.stderr000066400000000000000000000000001256461075500256020ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_-help.stderr000066400000000000000000000000001256461075500266670ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_-recursive.stderr000066400000000000000000000000001256461075500277460ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_-recursive_-expand-dots.stderr000066400000000000000000000000001256461075500323310ustar00rootroot00000000000000main.exe_help_-recursive_-expand-dots_-flags.stderr000066400000000000000000000000001256461075500335030ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputcore-113.00.00/test/command-tests/expected-output/main.exe_help_-recursive_-flags.stderr000066400000000000000000000000001256461075500311770ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_adverb.stderr000066400000000000000000000000001256461075500271250ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_adverb_-recursive.stderr000066400000000000000000000000001256461075500312710ustar00rootroot00000000000000main.exe_help_adverb_-recursive_-expand-dots.stderr000066400000000000000000000000001256461075500335750ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputmain.exe_help_adverb_-recursive_-expand-dots_-flags.stderr000066400000000000000000000000001256461075500350260ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputcore-113.00.00/test/command-tests/expected-output/main.exe_help_adverb_-recursive_-flags.stderr000066400000000000000000000000001256461075500325220ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_help.stderr000066400000000000000000000000001256461075500266120ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_help_-recursive.stderr000066400000000000000000000000001256461075500307560ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_help_-recursive_-expand-dots.stderr000066400000000000000000000000001256461075500333410ustar00rootroot00000000000000main.exe_help_help_-recursive_-expand-dots_-flags.stderr000066400000000000000000000000001256461075500345130ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputcore-113.00.00/test/command-tests/expected-output/main.exe_help_help_-recursive_-flags.stderr000066400000000000000000000000001256461075500322070ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_jab.stderr000066400000000000000000000000001256461075500264160ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_jab_-recursive.stderr000066400000000000000000000000001256461075500305620ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_jab_-recursive_-expand-dots.stderr000066400000000000000000000000001256461075500331450ustar00rootroot00000000000000main.exe_help_jab_-recursive_-expand-dots_-flags.stderr000066400000000000000000000000001256461075500343170ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputcore-113.00.00/test/command-tests/expected-output/main.exe_help_jab_-recursive_-flags.stderr000066400000000000000000000000001256461075500320130ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_nested.stderr000066400000000000000000000000001256461075500271440ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_help_nested_-recursive.stderr000066400000000000000000000000001256461075500313100ustar00rootroot00000000000000main.exe_help_nested_-recursive_-expand-dots.stderr000066400000000000000000000000001256461075500336140ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputmain.exe_help_nested_-recursive_-expand-dots_-flags.stderr000066400000000000000000000000001256461075500350450ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-outputcore-113.00.00/test/command-tests/expected-output/main.exe_help_nested_-recursive_-flags.stderr000066400000000000000000000000001256461075500325410ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_jab_-fondue_-happy.stderr000066400000000000000000000000001256461075500303010ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_jab_-happy.stderr000066400000000000000000000000001256461075500266640ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_jab_-help.stderr000066400000000000000000000000001256461075500264730ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_jab_123.stderr000066400000000000000000000000001256461075500257730ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_jab_123_-happy.stderr000066400000000000000000000000001256461075500272510ustar00rootroot00000000000000core-113.00.00/test/command-tests/expected-output/main.exe_nested_-help.stderr000066400000000000000000000000001256461075500272210ustar00rootroot00000000000000core-113.00.00/test/command-tests/lib/000077500000000000000000000000001256461075500172625ustar00rootroot00000000000000core-113.00.00/test/command-tests/lib/main.ml000066400000000000000000000017121256461075500205410ustar00rootroot00000000000000TEST_MODULE = struct open Core.Std (* Required by demo_parent.exe and demo_child.exe: *) let () = Unix.putenv ~key:"ENVVAR" ~data:"test" let command = Command.exec () ~summary:"constructed Command.t" ~path_to_exe:(`Relative_to_me "../demo_grandparent.exe") let subcommands t = let rec loop : Command.Shape.t -> _ = function | Basic -> [] | Group subs -> subs | Exec thunk -> loop (thunk ()) in loop (Command.shape t) let rec subcommand_hierarchy t : Sexp.t = let subs = subcommands t in List (List.map subs ~f:(fun (sub, t) -> Sexp.List [Atom sub; subcommand_hierarchy t])) TEST_UNIT = <:test_result< Sexp.t >> (subcommand_hierarchy command) ~expect:(Sexp.of_string "((help ()) \ \n (version ()) \ \n (parent ( \ \n (help ()) \ \n (version ()) \ \n (child ()))))") end core-113.00.00/test/command-tests/test-completion.t000066400000000000000000000051651256461075500220360ustar00rootroot00000000000000Here we demonstrate tab completion $ demo_help.exe help -recursive this command does stuff demo_help.exe SUBCOMMAND === subcommands === jab this command does stuff here jib this command does stuff here adverb this command does more stuff . drolly this command does stuff here . opposable this command does stuff here with-body this command does more stuff . drolly this command does stuff here . opposable this command does stuff here ordered group with unsorted subcommands . zzz this command does stuff here . aaa this command does stuff here version print version information help explain a given subcommand (perhaps recursively) Tab completion works for subcommands ... $ tab_complete demo_help.exe '' adverb help jab jib ordered version with-body $ tab_complete demo_help.exe 'j' jab jib $ tab_complete demo_help.exe 'jab' jab ... at all positions in the command hierarchy. $ tab_complete demo_help.exe adverb '' drolly help opposable $ tab_complete demo_help.exe adverb 'dr' drolly Tab completion works for flag names. $ tab_complete demo_help.exe jab '-' -help -ping -pong $ tab_complete demo_help.exe jab '-p' -ping -pong $ tab_complete demo_help.exe jab '-pi' -ping $ tab_complete demo_help.exe jab '-ping' -ping Tab completion works for [Arg_type.t] values which have defined it: both for flag arguments ... $ tab_complete demo_help.exe jab -pong '' baa\ baa bar baz foo $ tab_complete demo_help.exe jab -pong 'ba' baa\ baa bar baz $ tab_complete demo_help.exe jab -pong 'bar' bar ... and anonymous arguments (assumed not to be flags). $ tab_complete demo_help.exe jab '' baa\ baa bar baz foo $ tab_complete demo_help.exe jab 'ba' baa\ baa bar baz $ tab_complete demo_help.exe jab 'bar' bar It continues to work even if one of the previous values failed to parse. $ tab_complete demo_help.exe jab FeO 'ba' baa\ baa bar baz $ demo_help.exe jab FeO bar this command does stuff here demo_help.exe jab OXIDE DIODE [PATH] Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et ante a nibh scelerisque ultrices. Fusce consectetur dictum ante quis commodo. === flags === [-ping] make sure ping is doing the same stuff [-pong NAME] which pong should do the stuff [-help] print this help text and exit (alias: -?) failed to parse OXIDE value "FeO" (Failure "valid arguments: {baa\\ baa,bar,baz,foo}") [1] core-113.00.00/test/command-tests/test-exec.t000066400000000000000000000055701256461075500206110ustar00rootroot00000000000000parent.exe and child.exe are separate executables, but the "child" subcommand of the former is defined as a Command.exec of the latter. $ ENVVAR=test demo_parent.exe -help parent part of Command.exec demo demo_parent.exe SUBCOMMAND === subcommands === child this command is in another executable version print version information help explain a given subcommand (perhaps recursively) $ ENVVAR=test demo_child.exe -help child part of Command.exec demo demo_child.exe NUM [BOOL] readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. === flags === -date DATE a required date argument [-file FILE] an optional file argument [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) Help works across Command.exec $ ENVVAR=test demo_parent.exe child -help child part of Command.exec demo demo_child.exe NUM [BOOL] readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. readme text. === flags === -date DATE a required date argument [-file FILE] an optional file argument [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) So does tab completion $ ENVVAR=test tab_complete demo_parent.exe child - -build-info -date -file -help -version This works for multiple levels of nesting as well $ ENVVAR=test demo_grandparent.exe help -r -f grandparent part of Command.exec demo demo_grandparent.exe SUBCOMMAND === subcommands and flags === parent this command is in another executable . child this command is in another executable . . -date DATE a required date argument . . [-file FILE] an optional file argument . . [-build-info] print info about this build and exit . . [-version] print the version of this build and exit . version print version information . . [-build-info] print build info for this build . . [-version] print the version of this build version print version information . [-build-info] print build info for this build . [-version] print the version of this build help explain a given subcommand (perhaps recursively) . [-expand-dots] expand subcommands in recursive help . [-flags] show flags as well in recursive help . [-recursive] show subcommands of subcommands, etc. core-113.00.00/test/command-tests/test-full-flag.t000066400000000000000000000053411256461075500215320ustar00rootroot00000000000000Help still lists the aliases $ demo_full_flag.exe -help Test full flag validation demo_full_flag.exe Simple readme === flags === [-full-flag-not-required] make sure that prefix matches still work (alias: -full-alias-not-required) [-full-flag-required] make sure if the full argument is not provided, command bails (alias: -full-alias-required) [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) If you do not provide the full flag: error $ demo_full_flag.exe -full-flag-requi Test full flag validation demo_full_flag.exe Simple readme === flags === [-full-flag-not-required] make sure that prefix matches still work (alias: -full-alias-not-required) [-full-flag-required] make sure if the full argument is not provided, command bails (alias: -full-alias-required) [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) unknown flag -full-flag-requi [1] If you do not provide the full alias: error $ demo_full_flag.exe -full-alias-requi Test full flag validation demo_full_flag.exe Simple readme === flags === [-full-flag-not-required] make sure that prefix matches still work (alias: -full-alias-not-required) [-full-flag-required] make sure if the full argument is not provided, command bails (alias: -full-alias-required) [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) unknown flag -full-alias-requi [1] If you provide the full flag: success. $ demo_full_flag.exe -full-flag-required passed the un-abbreviatable flag doing stuff here! Or the alias. $ demo_full_flag.exe -full-alias-required passed the un-abbreviatable flag doing stuff here! But prefix matches still work $ demo_full_flag.exe -full-flag-no passed the abbreviatable flag doing stuff here! Even on aliases $ demo_full_flag.exe -full-alias-no passed the abbreviatable flag doing stuff here! core-113.00.00/test/command-tests/test-help.t000066400000000000000000000230601256461075500206070ustar00rootroot00000000000000Every Command-built exe supports a help subcommand which shows all other subcommands along with their descriptions $ demo_help.exe help this command does stuff demo_help.exe SUBCOMMAND === subcommands === jab this command does stuff here jib this command does stuff here adverb this command does more stuff with-body this command does more stuff ordered group with unsorted subcommands version print version information help explain a given subcommand (perhaps recursively) It can be used to show the entire command hierarchy $ demo_help.exe help -recursive this command does stuff demo_help.exe SUBCOMMAND === subcommands === jab this command does stuff here jib this command does stuff here adverb this command does more stuff . drolly this command does stuff here . opposable this command does stuff here with-body this command does more stuff . drolly this command does stuff here . opposable this command does stuff here ordered group with unsorted subcommands . zzz this command does stuff here . aaa this command does stuff here version print version information help explain a given subcommand (perhaps recursively) And the flags for leaf commands. $ demo_help.exe help -recursive -flags this command does stuff demo_help.exe SUBCOMMAND === subcommands and flags === jab this command does stuff here . [-ping] make sure ping is doing the same stuff . [-pong NAME] which pong should do the stuff jib this command does stuff here . [-ping] make sure ping is doing the same stuff . [-pong NAME] which pong should do the stuff adverb this command does more stuff . drolly this command does stuff here . . [-ping] make sure ping is doing the same stuff . . [-pong NAME] which pong should do the stuff . opposable this command does stuff here . . [-ping] make sure ping is doing the same stuff . . [-pong NAME] which pong should do the stuff with-body this command does more stuff . drolly this command does stuff here . . [-ping] make sure ping is doing the same stuff . . [-pong NAME] which pong should do the stuff . opposable this command does stuff here . . [-ping] make sure ping is doing the same stuff . . [-pong NAME] which pong should do the stuff ordered group with unsorted subcommands . zzz this command does stuff here . . [-ping] make sure ping is doing the same stuff . . [-pong NAME] which pong should do the stuff . aaa this command does stuff here . . [-ping] make sure ping is doing the same stuff . . [-pong NAME] which pong should do the stuff version print version information . [-build-info] print build info for this build . [-version] print the version of this build help explain a given subcommand (perhaps recursively) . [-expand-dots] expand subcommands in recursive help . [-flags] show flags as well in recursive help . [-recursive] show subcommands of subcommands, etc. Oh look, there is another flag for the help subcommand. It fills in all the contextual dots in the output, which is helpful when viewing diffs of help output. $ demo_help.exe help -recursive -flags -expand-dots this command does stuff demo_help.exe SUBCOMMAND === subcommands and flags === jab this command does stuff here jab [-ping] make sure ping is doing the same stuff jab [-pong NAME] which pong should do the stuff jib this command does stuff here jib [-ping] make sure ping is doing the same stuff jib [-pong NAME] which pong should do the stuff adverb this command does more stuff adverb drolly this command does stuff here adverb drolly [-ping] make sure ping is doing the same stuff adverb drolly [-pong NAME] which pong should do the stuff adverb opposable this command does stuff here adverb opposable [-ping] make sure ping is doing the same stuff adverb opposable [-pong NAME] which pong should do the stuff with-body this command does more stuff with-body drolly this command does stuff here with-body drolly [-ping] make sure ping is doing the same stuff with-body drolly [-pong NAME] which pong should do the stuff with-body opposable this command does stuff here with-body opposable [-ping] make sure ping is doing the same stuff with-body opposable [-pong NAME] which pong should do the stuff ordered group with unsorted subcommands ordered zzz this command does stuff here ordered zzz [-ping] make sure ping is doing the same stuff ordered zzz [-pong NAME] which pong should do the stuff ordered aaa this command does stuff here ordered aaa [-ping] make sure ping is doing the same stuff ordered aaa [-pong NAME] which pong should do the stuff version print version information version [-build-info] print build info for this build version [-version] print the version of this build help explain a given subcommand (perhaps recursively) help [-expand-dots] expand subcommands in recursive help help [-flags] show flags as well in recursive help help [-recursive] show subcommands of subcommands, etc. Every subcommand which itself has subcommands has a help subcommand among them. There is a -help flag that works $ demo_help.exe adverb help this command does more stuff demo_help.exe adverb SUBCOMMAND Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et ante a nibh scelerisque ultrices. Fusce consectetur dictum ante quis commodo. === subcommands === drolly this command does stuff here opposable this command does stuff here help explain a given subcommand (perhaps recursively) Every command in the hierarchy also takes a -help flag. For group commands, the -help flag behaves just like the help subcommand $ demo_help.exe -help this command does stuff demo_help.exe SUBCOMMAND === subcommands === jab this command does stuff here jib this command does stuff here adverb this command does more stuff with-body this command does more stuff ordered group with unsorted subcommands version print version information help explain a given subcommand (perhaps recursively) $ demo_help.exe adverb -help this command does more stuff demo_help.exe adverb SUBCOMMAND Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et ante a nibh scelerisque ultrices. Fusce consectetur dictum ante quis commodo. === subcommands === drolly this command does stuff here opposable this command does stuff here help explain a given subcommand (perhaps recursively) For leaf commands, it shows all available flags, along with their documentation. $ demo_help.exe adverb drolly -help this command does stuff here demo_help.exe adverb drolly OXIDE DIODE [PATH] Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et ante a nibh scelerisque ultrices. Fusce consectetur dictum ante quis commodo. === flags === [-ping] make sure ping is doing the same stuff [-pong NAME] which pong should do the stuff [-help] print this help text and exit (alias: -?) We can ask for help on the help subcommand itself $ demo_help.exe help -help explain a given subcommand (perhaps recursively) demo_help.exe help [SUBCOMMAND] === flags === [-expand-dots] expand subcommands in recursive help [-flags] show flags as well in recursive help [-recursive] show subcommands of subcommands, etc. [-help] print this help text and exit (alias: -?) We see that help subcommands can also be passed an argument: one of their sibling subcommands. $ demo_help.exe help jab this command does stuff here demo_help.exe jab OXIDE DIODE [PATH] Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et ante a nibh scelerisque ultrices. Fusce consectetur dictum ante quis commodo. === flags === [-ping] make sure ping is doing the same stuff [-pong NAME] which pong should do the stuff [-help] print this help text and exit (alias: -?) This provides another way to ask for help on help. $ demo_help.exe help help explain a given subcommand (perhaps recursively) demo_help.exe help [SUBCOMMAND] === flags === [-expand-dots] expand subcommands in recursive help [-flags] show flags as well in recursive help [-recursive] show subcommands of subcommands, etc. [-help] print this help text and exit (alias: -?) core-113.00.00/test/command-tests/test-hook.t000066400000000000000000000014021256461075500206130ustar00rootroot00000000000000Every Command-built exe supports a help subcommand which shows all other subcommands along with their descriptions $ demo_help.exe adverb this command does more stuff demo_help.exe adverb SUBCOMMAND Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et ante a nibh scelerisque ultrices. Fusce consectetur dictum ante quis commodo. === subcommands === drolly this command does stuff here opposable this command does stuff here help explain a given subcommand (perhaps recursively) missing subcommand for command demo_help.exe adverb [1] $ demo_help.exe with-body BEGIN body code path = (demo_help.exe with-body) (running this instead of reporting a missing subcommand) END body code core-113.00.00/test/command-tests/test-internals.t000066400000000000000000000015551256461075500216630ustar00rootroot00000000000000Each leaf command in demo_internals.exe knows - its position in the command hierarchy via Command.Spec.path, - its list of unprocessed arguments via Command.Spec.args, and - its own help message via Command.Spec.help. The leaf commands themselves just print out this information. $ demo_internals.exe foo 1 -foo 2 path = (demo_internals.exe foo) args = (1 -foo 2) help = summary demo_internals.exe foo [BAR] === flags === [-foo NUM] flag value [-help] print this help text and exit (alias: -?) Here is one deeper in the hierarchy: $ demo_internals.exe bar baz 1 -foo 2 path = (demo_internals.exe bar baz) args = (1 -foo 2) help = summary demo_internals.exe bar baz [BAR] === flags === [-foo NUM] flag value [-help] print this help text and exit (alias: -?) core-113.00.00/test/command-tests/test-no-arg-abort.t000066400000000000000000000031771256461075500221560ustar00rootroot00000000000000Demonstrating the use of Command.Spec.no_arg_abort. $ demo_no_arg_abort.exe -help demonstrate the no_arg_abort flag type demo_no_arg_abort.exe [NUM] === flags === [-foo NUM] numeric flag [-grammar] display GRAMMAR.txt and quit [-readme] display README.txt and quit [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) $ demo_no_arg_abort.exe -foo 1 2 entering main with args: ((foo (1)) (anon (2))) doing stuff ... The -grammar and -readme flags are no_arg_abort flags, meaning that they cause us to quit parsing the command line and exit. $ demo_no_arg_abort.exe -readme -foo non-int blah blah blah This is the contents of README.txt. $ demo_no_arg_abort.exe -grammar -foo non-int blah blah blah This is the contents of GRAMMAR.txt. Whichever no_arg_abort flag comes first is the one that is run. $ demo_no_arg_abort.exe -readme -grammar This is the contents of README.txt. Of course, the command line must be well-formed up to the no_arg_abort flag. $ demo_no_arg_abort.exe -ok non-int -readme demonstrate the no_arg_abort flag type demo_no_arg_abort.exe [NUM] === flags === [-foo NUM] numeric flag [-grammar] display GRAMMAR.txt and quit [-readme] display README.txt and quit [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) unknown flag -ok [1] core-113.00.00/test/command-tests/test-one-or-more.t000066400000000000000000000026321256461075500220200ustar00rootroot00000000000000This command has both flags and anons that must be passed at least once $ demo_one_or_more.exe -help Command.Spec.{one_or_more,non_empty_sequence} demo demo_one_or_more.exe Y [Y ...] === flags === -foo X required listed flag [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) $ demo_one_or_more.exe 1 2 3 -foo a -foo b -foo c ((xs (a b c)) (ys (1 2 3))) $ demo_one_or_more.exe 1 -foo a ((xs (a)) (ys (1))) $ demo_one_or_more.exe -foo a Command.Spec.{one_or_more,non_empty_sequence} demo demo_one_or_more.exe Y [Y ...] === flags === -foo X required listed flag [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) missing anonymous argument: Y [1] $ demo_one_or_more.exe 1 Command.Spec.{one_or_more,non_empty_sequence} demo demo_one_or_more.exe Y [Y ...] === flags === -foo X required listed flag [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) missing required flag: -foo [1] core-113.00.00/test/command-tests/test-sexp-load.t000066400000000000000000000026271256461075500215610ustar00rootroot00000000000000If we call Sexp.load_conv_exn inside command line parsing code, we get a stack trace and a source file location pointing to where the problem is. $ demo_sexp_load.exe $TEST_ETC/malformed.sexp demonstrate sexp loading during command line parsing demo_sexp_load.exe CONFIG-FILE === flags === [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?) Uncaught exception: (Sexplib.Conv.Of_sexp_error (Sexplib.Sexp.Annotated.Conv_exn */lib/core/test/command-tests/etc/malformed.sexp:1:0 (glob) (Failure "demo_sexp_load.ml.config_of_sexp: the following record elements were undefined: bar")) ((foo 3))) (Raised|Re-raised|Called) (at|from) file ".*", line \d+, characters .* (re) (Raised|Re-raised|Called) (at|from) file ".*", line \d+, characters .* (re) (Raised|Re-raised|Called) (at|from) file ".*", line \d+, characters .* (re) (Raised|Re-raised|Called) (at|from) file ".*", line \d+, characters .* (re) (Raised|Re-raised|Called) (at|from) file ".*", line \d+, characters .* (re) (Raised|Re-raised|Called) (at|from) file ".*", line \d+, characters .* (re) (Raised|Re-raised|Called) (at|from) file ".*", line \d+, characters .* (re) (Raised|Re-raised|Called) (at|from) file ".*", line \d+, characters .* (re) [1] core-113.00.00/test/command-tests/test-version.t000066400000000000000000000026771256461075500213570ustar00rootroot00000000000000Every group command gets a version subcommand. $ demo_help.exe version -help print version information demo_help.exe version === flags === [-build-info] print build info for this build [-version] print the version of this build [-help] print this help text and exit (alias: -?) Build-info says interesting things about the context in which the executable was built: Who built it? Where and when did they build it? Using what version of linux and ocaml? $ demo_help.exe version -build-info ((username *) (hostname *) (kernel *) (build_date *) (build_time *) (x_library_inlining *) (ocaml_version *) (executable_path *) (build_system *) (nodynlink *) (packing *)) (glob) The version flag shows what hg versions of what clones were built. $ demo_help.exe version -version (.*?) (re) If you fail to specify -version or -build-info, you get both. $ demo_help.exe version ((username *) (hostname *) (kernel *) (build_date *) (build_time *) (x_library_inlining *) (ocaml_version *) (executable_path *) (build_system *) (nodynlink *) (packing *)) (glob) (.*?) (re) The -version and -build-info flags also work for the top-level command. $ demo_help.exe -build-info ((username *) (hostname *) (kernel *) (build_date *) (build_time *) (x_library_inlining *) (ocaml_version *) (executable_path *) (build_system *) (nodynlink *) (packing *)) (glob) $ demo_help.exe -version (.*?) (re) core-113.00.00/test/common_test.ml000066400000000000000000000036001256461075500166160ustar00rootroot00000000000000open OUnit;; open Core.Std let test = "common" >::: [ "% and /%" >:: (fun () -> let gen_int_pair () = (Quickcheck_deprecated.uig (), abs (Quickcheck_deprecated.uig ())) in let modulus_invariant (a, b) = let r = a % b in let q = a /% b in r >= 0 && a = q * b + r in Quickcheck_deprecated.laws_exn "modulus invariant" 1000 gen_int_pair modulus_invariant ); "memoize" >:: (fun () -> let f x = x * x in let memo_f = Memo.general f in Quickcheck_deprecated.laws_exn "memoize" 1000 Quickcheck_deprecated.uig (fun i -> f i = memo_f i) ); "nan" >:: (fun () -> "fmin1" @? (Float.is_nan (Float.min 1. Float.nan)); "fmin2" @? (Float.is_nan (Float.min Float.nan 0.)); "fmin3" @? (Float.is_nan (Float.min Float.nan Float.nan)); "fmax1" @? (Float.is_nan (Float.max 1. Float.nan)); "fmax2" @? (Float.is_nan (Float.max Float.nan 0.)); "fmax3" @? (Float.is_nan (Float.max Float.nan Float.nan)); "fmin_inan1" @? (1. = (Float.min_inan 1. Float.nan)); "fmin_inan2" @? (0. = (Float.min_inan Float.nan 0.)); "fmin_inan3" @? (Float.is_nan (Float.min_inan Float.nan Float.nan)); "fmax_inan1" @? (1. = (Float.max_inan 1. Float.nan)); "fmax_inan2" @? (0. = (Float.max_inan Float.nan 0.)); "fmax_inan3" @? (Float.is_nan (Float.max_inan Float.nan Float.nan)); ); "round" >:: (fun () -> "zero" @? (Float.iround_exn ~dir:`Nearest 0.2 = 0); "negative zero" @? (Float.iround_exn ~dir:`Nearest (-0.2) = 0); "positive" @? (Float.iround_exn ~dir:`Nearest 3.4 = 3); "negative" @? (Float.iround_exn ~dir:`Nearest (-3.4) = -3); ); ] core-113.00.00/test/comparable_test.ml000066400000000000000000000116241256461075500174400ustar00rootroot00000000000000open OUnit;; open Core.Std module F (M : sig type t include Comparable.S with type t := t val one : t val two : t val three : t end) : sig val test : OUnit.test end = struct open M let equal = M.(=) let (=) = Bool.equal let test = let foreach f = f one; f two; f three in "comparable" >:: (fun () -> foreach (fun a -> foreach (fun b -> assert (equal (min a b) (min b a)); assert (equal (max a b) (max b a)); assert ((a < b) = (Int.(<) (compare a b) 0)); assert ((equal a b) = (Int.equal (compare a b) 0)); assert ((a > b) = (Int.(>) (compare a b) 0)); assert ((a < b) = (Int.(<) (ascending a b) 0)); assert ((equal a b) = (Int.equal (ascending a b) 0)); assert ((a > b) = (Int.(>) (ascending a b) 0)); assert ((a > b) = (Int.(<) (descending a b) 0)); assert ((equal a b) = (Int.(=) (descending a b) 0)); assert ((a < b) = (Int.(>) (descending a b) 0)); assert ((a > b) = (b < a)); assert ((a >= b) = (b <= a)); assert ((a < b) = not (a >= b)); assert ((a > b) = not (a <= b)); assert ((equal a b) = not (a <> b)); assert ((a >= b) = (a > b || equal a b)); assert ((a <= b) = (a < b || equal a b)))); assert (equal one one); assert (equal two two); assert (equal three three); assert (not (one < one)); assert (one < two); assert (one < three); assert (not (two < one)); assert (not (two < two)); assert (two < three); assert (not (three < one)); assert (not (three < two)); assert (not (three < three)); assert (equal (max one one) one); assert (equal (max one two) two); assert (equal (max one three) three); assert (equal (max two two) two); assert (equal (max two three) three); assert (equal (max three three) three); assert (equal (min one one) one); assert (equal (min one two) one); assert (equal (min one three) one); assert (equal (min two two) two); assert (equal (min two three) two); assert (equal (min three three) three); ) ;; end module Float = F (struct include Float let one = 1.0 let two = 2.0 let three = 3.0 end) module String = F (struct include String let one = "a" let two = "b" let three = "c" end) module Span = F (struct include Time.Span let one = of_sec (-1.0) let two = zero let three = of_sec 1.0 end) module Ofday = F (struct include Time.Ofday let one = of_span_since_start_of_day (Time.Span.of_sec 1.) let two = of_span_since_start_of_day (Time.Span.of_sec 2.) let three = of_span_since_start_of_day (Time.Span.of_sec 3.) end) module Date = F (struct include Date let zone = Time.Zone.local let one = Time.now () let two = Time.add one (Time.Span.of_hr 30.0) let three = Time.add two (Time.Span.of_hr 30.0) let one = Time.to_date one ~zone let two = Time.to_date two ~zone let three = Time.to_date three ~zone end) module Time = F (struct include Time let one = Time.now () let two = Time.add one (sec 1.) let three = Time.add two (sec 1.) end) module Int32 = F (struct include Int32 let one = Int32.one let two = 2l let three = 3l end) module Int64 = F (struct include Int64 let one = Int64.one let two = 2L let three = 3L end) module Nativeint = F (struct include Nativeint let one = of_int 1 let two = of_int 2 let three = of_int 3 end) module Int' = F (struct type t = Int.t include Comparable.Make (Int) let one = 1 let two = 2 let three = 3 end) module Int'' = F (struct type t = int include Comparable.Inherit (Int) (struct include Int let component x = x end) let one = 1 let two = 2 let three = 3 end) module Int = F (struct include Int let one = 1 let two = 2 let three = 3 end) let lexicographic_test = "lexicographic" >:: (fun () -> "1 0" @? (Comparable.lexicographic [compare] 1 1 = 0); "1 -1" @? (Comparable.lexicographic [compare] 1 2 = -1); "1 1" @? (Comparable.lexicographic [compare] 2 1 = 1); let cmp = Array.to_list (Array.init 3 ~f:(fun i a b -> compare a.(i) b.(i))) in "3 0" @? (Comparable.lexicographic cmp [|1;2;3;4|] [|1;2;3;9|] = 0); "3 -1" @? (Comparable.lexicographic cmp [|1;2;3;4|] [|1;2;4;9|] = -1); "3 1" @? (Comparable.lexicographic cmp [|1;2;3;4|] [|1;1;4;9|] = 1); ) let test = TestList [Float.test; String.test; Float.test; Span.test; Ofday.test; Date.test; Time.test; Int.test; Int32.test; Int64.test; Nativeint.test; Int'.test; Int''.test; lexicographic_test; ] ;; core-113.00.00/test/condition_test.ml000066400000000000000000000040111256461075500173110ustar00rootroot00000000000000(* Test Condition.timedwait *) (* This only tests the pthread_cond_timedwait wrapper and not the underlying unix function. Both branches (timeout, success) are tested; all the possible race conditions are assumed to be handled properly by pthread and not tested. *) open Core.Std open OUnit let rec run ~num_retries = let v_mtx = Mutex.create () and cnd_v_is_true = Condition.create () and v = ref false in let v_setter () = Thread.delay 0.1; Mutex.lock v_mtx; v := true; Condition.signal cnd_v_is_true; Mutex.unlock v_mtx; in let wait_for_v tmout = let timeout = Unix.gettimeofday () +. tmout in not (Condition.timedwait cnd_v_is_true v_mtx (Time.of_float timeout)) in Mutex.lock v_mtx; (* This condition wait is expected to timeout. *) begin let timedout = wait_for_v 0.1 in assert timedout end; ignore (Thread.create v_setter ():Thread.t); (* Now we have a thread that sets the condition so we expect to not timeout. *) begin let rec wait ~num_wait_retries = if num_wait_retries = 0 then failwithf "condition_test repeatedly failed %d times" num_wait_retries () else let timed_out = wait_for_v 0.5 in match !v, timed_out with | true, false -> (* The expected case. Yay. *) () | false, false -> (* Should be impossible to get here, since [v_setter] set [v] before signaling. *) assert false | false, true -> (* We timed out. Maybe machine is loaded. Try again. *) wait ~num_wait_retries:(num_wait_retries - 1) | true, true -> (* We timed out and the variable was set. Could happen due to a race. Try the whole experiment again. *) run ~num_retries:(num_retries - 1) in wait ~num_wait_retries:10 end ;; let test = "Condition_test" >::: [ "test" >:: (fun () -> "1" @? (try run ~num_retries:5; true with e -> eprintf "in cond\ ition test:%s\n%!" (Exn.to_string e); false)); ] core-113.00.00/test/container_test.ml000066400000000000000000000017341256461075500173160ustar00rootroot00000000000000open Core.Std module Test_S1 (M : sig include Container.S1 val of_list : 'a list -> 'a t end) : sig val test : unit -> unit end = struct let lists = List.init 10 ~f:(fun i -> List.init i ~f:ident) let test () = List.iter lists ~f:(fun l -> let m = M.of_list l in assert (M.length m = List.length l); assert (M.is_empty m = List.is_empty l); let is_l_unsorted l' = l = List.sort l' ~cmp:Int.compare in assert (is_l_unsorted (M.fold m ~init:[] ~f:(fun ac x -> x :: ac))); assert (is_l_unsorted (M.to_list m)); let r = ref [] in M.iter m ~f:(fun x -> r := x :: !r); assert (is_l_unsorted !r); assert (is_l_unsorted (Array.to_list (M.to_array m))); List.iter l ~f:(fun x -> assert (M.exists m ~f:(fun x' -> x = x'))); assert (M.for_all m ~f:(fun x -> List.exists l ~f:(fun x' -> x = x'))); List.iter l ~f:(fun x -> assert (Some x = M.find m ~f:(fun x' -> x = x'))); ) ;; end core-113.00.00/test/core_array_test.ml000066400000000000000000000112321256461075500174540ustar00rootroot00000000000000open OUnit;; open Core.Std open Array let ar1 = [|1;2;3;4;5;6;7;8;9;10|] let ( =|= ) list array = list = Array.to_list array let test = "core_array" >::: [ "slice" >:: (fun () -> "all" @? (slice ar1 0 0 = ar1); "ordinary" @? (slice ar1 1 3 = [|2;3|]); "neg1" @? (slice ar1 0 (-1) = [|1;2;3;4;5;6;7;8;9|]); "neg2" @? (slice ar1 (-1) 0 = [|10|]); "neg3" @? (slice ar1 (-5) (-4) = [|6|];) ); "nget" >:: (fun () -> "neg" @? (nget ar1 (-3) = 8); "pos" @? (nget ar1 3 = ar1.(3)); "invalid" @? (try ignore (nget ar1 (-100)); false with Invalid_argument _ -> true | _ -> false) ); "filter_opt" >:: (fun () -> "none" @? (filter_opt [|None;None;None|] = [||]); "single" @? (filter_opt [|None;Some 3;None|] = [|3|]); "singlef" @? (filter_opt [|None;Some 3.;None|] = [|3.|]); "double" @? (filter_opt [|None; Some 3; Some 4|] = [|3;4|]); ); "swap" >:: (fun () -> let array = [|0; 1; 2; 3|] in "same" @? (swap array 0 0; array = [|0; 1; 2; 3|]); "different" @? (swap array 0 3; array = [|3; 1; 2; 0|]); ); "exists" >:: (fun () -> let list = List.init ~f:(fun _ -> Random.int 1000) 1000 in let array = Array.of_list list in "list1" @? (List.exists ~f:((=) 1) list = Array.exists ~f:((=) 1) array); "list2" @? (List.exists ~f:((=) 2) list = Array.exists ~f:((=) 2) array); "list3" @? (List.exists ~f:((=) 3) list = Array.exists ~f:((=) 3) array); "list4" @? (List.exists ~f:((=) 4) list = Array.exists ~f:((=) 4) array); ); "for_all" >:: (fun () -> let list = Quickcheck_deprecated.lg (fun () -> Random.int 1000) ~size_gen:(fun _ -> 1000) () in let array = Array.of_list list in "list1" @? (List.for_all ~f:((<>) 1) list = Array.for_all ~f:((<>) 1) array); "list2" @? (List.for_all ~f:((<>) 2) list = Array.for_all ~f:((<>) 2) array); "list3" @? (List.for_all ~f:((<>) 3) list = Array.for_all ~f:((<>) 3) array); "list4" @? (List.for_all ~f:((<>) 4) list = Array.for_all ~f:((<>) 4) array); ); "mem" >:: (fun () -> let list = Quickcheck_deprecated.lg (fun () -> Random.int 1000) ~size_gen:(fun _ -> 1000) () in let array = Array.of_list list in "list1" @? (List.mem list 1 = Array.mem array 1); "list2" @? (List.mem list 2 = Array.mem array 2); "list3" @? (List.mem list 3 = Array.mem array 3); "list4" @? (List.mem list 4 = Array.mem array 4); ); "rev" >:: (fun () -> let ordered_list = List.init 100 ~f:(fun i -> i) in let empty_list = [] in let one_list = [0] in "ordered" @? (let ordered_array = Array.of_list ordered_list in Array.rev_inplace ordered_array; List.rev ordered_list =|= ordered_array); "empty" @? (let empty_array = Array.of_list empty_list in Array.rev_inplace empty_array; List.rev empty_list =|= empty_array); "one" @? (let one_array = Array.of_list one_list in Array.rev_inplace one_array; List.rev one_list =|= one_array); ); "replace_all" >:: (fun () -> let random_list = Quickcheck_deprecated.lg (fun () -> Random.int 1000) ~size_gen:(fun _ -> 1000) () in let empty_list = [] in let one_list = [0] in let f i = i * i in "random" @? (let random_array = Array.of_list random_list in Array.replace_all ~f random_array; List.map ~f random_list =|= random_array); "empty" @? (let empty_array = Array.of_list empty_list in Array.replace_all ~f empty_array; List.map ~f empty_list =|= empty_array); "one" @? (let one_array = Array.of_list one_list in Array.replace_all ~f one_array; List.map ~f one_list =|= one_array); ); "cartesian_product" >:: (fun () -> "empty1" @? is_empty (cartesian_product [||] [||]); "empty2" @? is_empty (cartesian_product [||] [|13|]); "empty3" @? is_empty (cartesian_product [|13|] [||]); "simple" @? (cartesian_product [|1; 2; 3;|] [|"a"; "b";|] = [|(1, "a"); (1, "b"); (2, "a"); (2, "b"); (3, "a"); (3, "b");|])); ] core-113.00.00/test/core_char_test.ml000066400000000000000000000005521256461075500172560ustar00rootroot00000000000000open Core.Std open OUnit let of_string_test () = Char.of_string "c" = 'c' && Result.is_error (Result.try_with (fun () -> Char.of_string "")) && Result.is_error (Result.try_with (fun () -> Char.of_string "too long")) ;; let test = "core_char" >::: [ "to_string_hum" >:: (fun () -> "of_string" @? of_string_test (); ) ] core-113.00.00/test/core_filename_test.ml000066400000000000000000000011341256461075500201160ustar00rootroot00000000000000open OUnit;; open Core.Std let concat_test p1 p2 res = (sprintf "%s ^/ %s" p1 p2) @? (if p1 ^/ p2 = res then true else begin eprintf "%s ^/ %s = %s (expected %s)" p1 p2 (p1 ^/ p2) res; false end) let test = "core_filename" >::: [ "concat" >:: fun () -> (List.iter ~f:(fun (p1,p2,expected) -> concat_test p1 p2 expected) ["a/","/b","a/b"; "a","./b","a/b"; "a",".","a/."; "a","/","a/"; "a/.","./","a/"; "a///././/./.",".///././/././/b","a/b" ] ) ] core-113.00.00/test/core_int_test.ml000066400000000000000000000014441256461075500171340ustar00rootroot00000000000000open Core.Std open OUnit let esc_test i = int_of_string (Int.to_string_hum i) = i let bound = 2 lsl 10 let rand state = let rec aux acc cnt = if cnt = 0 then acc else let bit = if Random.State.bool state then 1 else 0 in aux (2*acc + bit) (cnt -1) in let aval = aux 1 (Random.State.int state (Sys.word_size - 3)) in if Random.State.bool state then - aval else aval (* Random with a distribution favouring small ones*) let test = "core_int" >::: [ "to_string_hum" >:: (fun () -> let state = Random.State.make [| 7; 4; 2 |] in "random" @? ( List.init ~f:(fun _ -> rand state) 10_000 |> List.for_all ~f:esc_test ); "max_int" @? esc_test Int.max_value; "min_int" @? esc_test Int.min_value ) ] core-113.00.00/test/core_map_test.ml000066400000000000000000000071631256461075500171230ustar00rootroot00000000000000open OUnit;; open Core.Std module StringMap = Map.Make (String) let m1 = StringMap.of_alist_exn ["a",1; "b",2; "c",3; "d",4] let m2 = StringMap.of_alist_exn ["a",1; "c",-3; "d",4; "e",5] let test = "core_fmap" >::: [ "merge1" >:: (fun () -> let f ~key:_ = function | `Left _ | `Right _ -> None | `Both (x, y) -> Some (x+y) in "eq1" @? StringMap.equal (=) (StringMap.merge ~f m1 m2) (StringMap.of_alist_exn ["a",2;"c",0;"d",8;]); "eq2" @? StringMap.equal (=) (StringMap.merge ~f m2 m1) (StringMap.of_alist_exn ["a",2;"c",0;"d",8;]); ); "merge2" >:: (fun () -> let f ~key:_ = function | `Left x -> Some x | `Right _ -> None | `Both (x, y) -> Some (x+y) in "eq" @? StringMap.equal (=) (StringMap.merge ~f m1 m2) (StringMap.of_alist_exn ["a",2;"b",2;"c",0;"d",8;]) ); "merge3" >:: (fun () -> let f ~key:_ = function | `Left x | `Right x -> Some x | `Both (x, y) -> Some (x+y) in "eq1" @? StringMap.equal (=) (StringMap.merge ~f m1 m2) (StringMap.of_alist_exn ["a",2;"b",2;"c",0;"d",8;"e",5]); "eq2" @? StringMap.equal (=) (StringMap.merge ~f m2 m1) (StringMap.of_alist_exn ["a",2;"b",2;"c",0;"d",8;"e",5]) ); "merge3" >:: (fun () -> let f ~key:_ = function | `Left x | `Right x -> Some x | `Both (x, y) -> Some (x+y) in "eq1" @? StringMap.equal (=) (StringMap.merge ~f m1 StringMap.empty) m1; "eq2" @? StringMap.equal (=) (StringMap.merge ~f StringMap.empty m1) m1; ); "sexp" >:: (fun () -> let s = "((a 1) (b 2) (c 3) (d 4))" in let m1' = StringMap.t_of_sexp int_of_sexp (Sexp.of_string s) in "of_sexp1" @? (StringMap.equal (=) m1' m1); let s_dup = "((a 1) (b 2) (a 3) (d 4))" in let s_dup = Sexp.of_string s_dup in try ignore (StringMap.t_of_sexp int_of_sexp s_dup); assert false with _ -> () ); "of_alist" >:: (fun () -> let a = [("a", 1); ("b", 2); ("c", 3); ("d", 4)] in let m = match StringMap.of_alist a with `Ok x -> x | `Duplicate_key _ -> failwith "argh" in "1" @? (StringMap.find_exn m "a" = 1 && StringMap.find_exn m "d" = 4); let a_dup = [("a", 1); ("b", 2); ("c", 3); ("b", 4); ("e", 5)] in "2" @? (match StringMap.of_alist a_dup with `Ok _ -> false | `Duplicate_key x -> x = "b"); "3" @? ((List.sort ~cmp:Poly.ascending (StringMap.to_alist (StringMap.of_alist_exn a))) = List.sort ~cmp:Poly.ascending a); try ignore (StringMap.of_alist_exn a_dup); assert false with _ -> () ); "for_all/exists" >:: (fun () -> let m = StringMap.of_alist_exn ["a",1;"b",2;"c",3;"d",4] in "1" @? (StringMap.for_all ~f:(fun x -> x > 0) m); "2" @? (not (StringMap.for_all ~f:(fun x -> x % 2 = 0) m)); "3" @? (StringMap.exists ~f:(fun x -> x % 2 = 0) m); "4" @? (not (StringMap.exists ~f:(fun x -> x < 0) m)); "short circuit forall" @? ( let sum = ref 0 in ignore (StringMap.for_all m ~f:(fun x -> sum := !sum + x; x <> 1)); !sum = 1 ); "short circuit exists" @? ( let sum = ref 0 in ignore (StringMap.exists m ~f:(fun x -> sum := !sum + x; x = 1)); !sum = 1 ); ); ] core-113.00.00/test/core_mutex_test.ml000066400000000000000000000012501256461075500174770ustar00rootroot00000000000000open Core.Std open OUnit let try_with_mutex f = let mtx = Mutex.create () in try f mtx; false with Sys_error _ -> true let check_double_lock () = try_with_mutex (fun mtx -> Mutex.lock mtx; Mutex.lock mtx) let check_unlock_unlocked () = try_with_mutex Mutex.unlock let check_unlock_other_locked () = try_with_mutex (fun mtx -> Thread.join (Thread.create (fun () -> Mutex.lock mtx) ()); Mutex.unlock mtx) let test = "core_mutex" >::: [ "error checking" >:: (fun () -> "double lock" @? check_double_lock (); "unlock unlocked" @? check_unlock_unlocked (); "unlock other locked" @? check_unlock_other_locked (); ) ] core-113.00.00/test/core_queue_test.ml000066400000000000000000000043711256461075500174700ustar00rootroot00000000000000open OUnit open Core.Std open Queue let test = "queue" >::: [ "create" >:: (fun () -> let t = create () in assert (is_empty t); ); "container" >:: (fun () -> let module T = Container_test.Test_S1 (Queue) in T.test (); ); "enqueue" >:: (fun () -> let t = create () in enqueue t 1; enqueue t 2; enqueue t 3; assert (to_list t = [1; 2; 3]); assert (peek t = Some 1); assert (dequeue t = Some 1); assert (to_list t = [2; 3]); assert (peek t = Some 2); assert (dequeue_exn t = 2); assert (to_list t = [3]); assert (peek_exn t = 3); assert (dequeue t = Some 3); assert (to_list t = []); assert (peek t = None); assert (dequeue t = None); ); "clear" >:: (fun () -> for i = 0 to 5 do let t = of_list (List.init i ~f:ident) in clear t; assert (is_empty t); done ); "copy" >:: (fun () -> let t = of_list [1; 2; 3] in let t' = copy t in ignore (dequeue t); assert (to_list t = [2; 3]); assert (to_list t' = [1; 2; 3]); ignore (clear t'); assert (to_list t = [2; 3]); assert (to_list t' = []); ); "blit_transfer" >:: (fun () -> for i1 = 0 to 3 do let l1 = List.init i1 ~f:ident in for i2 = 0 to 3 do let l2 = List.init i2 ~f:ident in let t1 = of_list l1 in let t2 = of_list l2 in blit_transfer ~src:t1 ~dst:t2 (); assert (is_empty t1); assert (to_list t2 = l2 @ l1); done done ); "filter_inplace" >:: (fun () -> let t = of_list [1; 2; 3; 4; 5; 6; 7] in filter_inplace t ~f:(fun n -> n mod 2 = 0); assert (to_list t = [2; 4; 6]); assert (for_all t ~f:(fun n -> n mod 2 = 0)); assert (exists t ~f:(fun n -> n = 4 || n = 6)); filter_inplace t ~f:(fun n -> n mod 2 <> 0); assert (to_list t = []); ); ] core-113.00.00/test/core_set_test.ml000066400000000000000000000041731256461075500171370ustar00rootroot00000000000000open OUnit open Core.Std module String_set = Set.Make(String) let s1 = String_set.of_list ["a"; "b"; "c"; "d"] (*let m2 = Map.of_alist ["a",1; "c",-3; "d",4; "e",5]*) type int_set = int Set.Poly.t with bin_io module String_set_comp = struct include Int.Replace_polymorphic_compare type string_set_comp = Int.t Set.Poly.t with compare let test () = let compare = compare_string_set_comp in assert (compare (Set.Poly.of_list []) (Set.Poly.of_list []) = 0); assert (compare (Set.Poly.of_list [0]) (Set.Poly.of_list []) <> 0); assert (compare (Set.Poly.of_list [3;2;1]) (Set.Poly.of_list [1;2;3]) = 0); assert (compare (Set.Poly.of_list [0;1;2;3]) (Set.Poly.of_list [1;1;2;3]) <> 0); end let test = "core_fset" >::: [ "sexp" >:: (fun () -> let s = "(a b c d)" in let s1' = String_set.t_of_sexp (Sexp.of_string s) in "of_sexp1" @? (String_set.equal s1' s1); let s_dup = "(a b a d)" in let s_dup = Sexp.of_string s_dup in assert_raises (Sexplib.Conv.Of_sexp_error ( Failure "Set.t_of_sexp: duplicate element in set", (sexp_of_string "a"))) (fun () -> String_set.t_of_sexp s_dup) ); "bin_io" >:: (fun () -> let max_n = 20 in let bstr = Bigstring.create (max_n + 1) in for n = 0 to max_n do let s1 = Set.Poly.of_array (Array.init n ~f:succ) in let pos = bin_write_int_set bstr ~pos:0 s1 in "pos" @? (pos = n + 1); let pos_ref = ref 0 in let s2 = bin_read_int_set bstr ~pos_ref in "pos_ref" @? (!pos_ref = n + 1); "equal" @? (Set.equal s1 s2); bstr.{0} <- '\002'; bstr.{1} <- 'x'; bstr.{2} <- 'x'; pos_ref := 0; let dup_check = try ignore (bin_read_int_set bstr ~pos_ref); false with Bin_prot.Common.Read_exc (Failure _, 3) -> true in "dup_check" @? dup_check done; ); "with_compare" >:: String_set_comp.test; ] core-113.00.00/test/core_string_speed_test.ml000066400000000000000000000030551256461075500210300ustar00rootroot00000000000000open Core.Std (* let escape = String.Escaping.escape ~escapeworthy:['%';'^'] ~escape_char:'\\' let escape_gen = String.Escaping.escape_gen ~escapeworthy_map:['%','%';'^','^'] ~escape_char:'\\' let unescape = String.Escaping.unescape ~escape_char:'\\' let unescape_gen = String.Escaping.unescape_gen ~map:[] ~escape_char:'\\' let () = let now = Utime.now () in for i = 1 to 500_000 do ignore (escape_gen "foo%bar\\^baz^quux%%%%%%%%%%%%%%%aoeusnthoaeusntaohusoaeusnatohunsaoehusnaoehusnaotusnaoehuasoenuht^^^^^^^^^") done; let later = Utime.now () in prerr_endline (Utime.span_to_string (Utime.abs_diff later now)); let now = Utime.now () in for i = 1 to 500_000 do ignore (escape "foo%bar\\^baz^quux%%%%%%%%%%%%%%%aoeusnthoaeusntaohusoaeusnatohunsaoehusnaoehusnaotusnaoehuasoenuht^^^^^^^^^") done; let later = Utime.now () in prerr_endline (Utime.span_to_string (Utime.abs_diff later now)); let now = Utime.now () in for i = 1 to 500_000 do ignore (unescape_gen "foo%bar\\^baz^quux\\s\\s\\s\\s\\s\\s\\s\\s%%%%%%%%%%%%%%%aoeusnthoaeusntaohusoaeusnatohunsaoehusnaoehusnaotusnaoehuasoenuht^^^^^^^^^") done; let later = Utime.now () in prerr_endline (Utime.span_to_string (Utime.abs_diff later now)); let now = Utime.now () in for i = 1 to 500_000 do ignore (unescape "foo%bar\\^baz^quux\\s\\s\\s\\s\\s\\s\\s\\s%%%%%%%%%%%%%%%aoeusnthoaeusntaohusoaeusnatohunsaoehusnaoehusnaotusnaoehuasoenuht^^^^^^^^^") done; let later = Utime.now () in prerr_endline (Utime.span_to_string (Utime.abs_diff later now)); *) core-113.00.00/test/core_string_test.ml000066400000000000000000000275741256461075500176640ustar00rootroot00000000000000open Core.Std open OUnit;; module S = String let str1 = "1234567890" let test = "core_string" >::: [ "slice" >:: (fun () -> "all" @? (S.slice str1 0 0 = str1); "ordinary" @? (S.slice str1 1 3= "23"); "neg1" @? (S.slice str1 0 (-1) = "123456789"); "neg2" @? (S.slice str1 (-1) 0 = "0"); "neg3" @? (S.slice str1 (-5) (-4) = "6";) ); "nget" >:: (fun () -> "neg" @? (S.nget str1 (-3) = '8'); "pos" @? (S.nget str1 3 = str1.[3]); "invalid" @? (try ignore (S.nget str1 (-100)); false with Invalid_argument _ -> true | _ -> false) ); "lsplit2_exn" >:: (fun () -> "none" @? (try ignore (S.lsplit2_exn str1 ~on:' '); false with Not_found -> true | _ -> false); "some1" @? (S.lsplit2_exn str1 ~on:'5' = ("1234","67890")); "some2" @? (S.lsplit2_exn "123.456.789" ~on:'.' = ("123","456.789")); ); "lsplit2" >:: (fun () -> "none" @? (S.lsplit2 str1 ~on:' ' = None); "some1" @? (S.lsplit2 str1 ~on:'5' = Some ("1234","67890")); "some2" @? (S.lsplit2 "123.456.789" ~on:'.' = Some ("123","456.789")); ); "rsplit2_exn" >:: (fun () -> "none" @? (try ignore (S.rsplit2_exn str1 ~on:' '); false with Not_found -> true | _ -> false); "some1" @? (S.rsplit2_exn str1 ~on:'5' = ("1234","67890")); "some2" @? (S.rsplit2_exn "123.456.789" ~on:'.' = ("123.456","789")); ); "rsplit2" >:: (fun () -> "none" @? (S.rsplit2 str1 ~on:' ' = None); "some1" @? (S.rsplit2 str1 ~on:'5' = Some ("1234","67890")); "some2" @? (S.rsplit2 "123.456.789" ~on:'.' = Some ("123.456","789")); ); "strip" >:: (fun () -> "both ends" @? (S.strip " 123 " = "123"); "all white" @? (S.strip "\n\t \n" = ""); "no white" @? (S.strip "as \t\ndf" = "as \t\ndf"); "just left" @? (S.strip " a" = "a"); "just right" @? (S.strip "a " = "a"); ); "lstrip" >:: (fun () -> "left" @? (S.lstrip " \t\r\n123 \t\n" = "123 \t\n"); "all white" @? (S.lstrip " \t \n\n\r " = ""); "no white on the left" @? (S.lstrip "foo Bar \n " = "foo Bar \n "); ); "rstrip" >:: (fun () -> "right" @? (S.rstrip " \t\r\n123 \t\n\r" = " \t\r\n123"); "all white" @? (S.rstrip " \t \n\n\r " = ""); "no white on the right" @? (S.rstrip " \n foo Bar" = " \n foo Bar"); ); "map" >:: (fun () -> "empty" @? (S.map ~f:(fun x -> x) "" = ""); "1" @? (S.map ~f:(function 'a' -> 'b' | 'b' -> 'a' | x -> x) "faboo" = "fbaoo"); ); "split" >:: (fun () -> "empty" @? (S.split "" ~on:'c' = [""]); "1" @? (S.split "c" ~on:'c' = ["";""]); "end" @? (S.split "fooc" ~on:'c' = ["foo";""]); "begin" @? (S.split "cfoo" ~on:'c' = ["";"foo"]); "beginend" @? (S.split "cfooc" ~on:'c' = ["";"foo";""]); "consecutive_delims" @? (S.split "bocci ball" ~on:'c' = ["bo"; ""; "i ball"]); ); "split_on_chars" >:: (fun () -> "empty" @? (S.split_on_chars "" ~on:['c'] = [""]); "1" @? (S.split_on_chars "c" ~on:['c'] = ["";""]); "1-grouped" @? (S.split_on_chars "chr" ~on:['h';'c';'r'] = ["";"";"";""]); "end" @? (S.split_on_chars "fooc" ~on:['c'] = ["foo";""]); "end-grouped" @? (S.split_on_chars "fooc" ~on:['c';'o'] = ["f";"";"";""]); "begin" @? (S.split_on_chars "cfoo" ~on:['c'] = ["";"foo"]); "begin-grouped" @? (S.split_on_chars "cfoo" ~on:['c';'f'] = ["";"";"oo"]); "consecutive_delims" @? (S.split_on_chars "bocci ball" ~on:['c'] = ["bo"; ""; "i ball"]); "consecutive_delims-grouped" @? (S.split_on_chars "bocci ball" ~on:['c';' ';'i'] = ["bo"; ""; ""; ""; "ball"]); ); "fold" >:: (fun () -> let to_list s = S.fold ~f:(fun acc c -> c::acc) ~init:[] s in "empty" @? (to_list "" = []); "singleton" @? (to_list "H" = ['H']); "simple" @? (to_list "Hello" = ['o';'l';'l';'e';'H']); ); "is_suffix" >:: (fun () -> "empty" @? (S.is_suffix "" ~suffix:"a" = false); "empty_empty_suffix" @? (S.is_suffix "" ~suffix:"" = true); "simple_empty_suffix" @? (S.is_suffix "Foo" ~suffix:"" = true); "singleton" @? (S.is_suffix "H" ~suffix:"H" = true); "simple" @? (S.is_suffix "Hello" ~suffix:"lo" = true); "simplefalse" @? (S.is_suffix "HelloFoo" ~suffix:"lo" = false); ); "is_prefix" >:: (fun () -> "empty" @? (S.is_prefix "" ~prefix:"a" = false); "empty_empty_prefix" @? (S.is_prefix "" ~prefix:"" = true); "simple_empty_prefix" @? (S.is_prefix "Foo" ~prefix:"" = true); "singleton" @? (S.is_prefix "H" ~prefix:"H" = true); "simple" @? (S.is_prefix "Hello" ~prefix:"He" = true); "simplefalse" @? (S.is_prefix "HelloFoo" ~prefix:"lo" = false); ); "concat_array" >:: (fun () -> "empty" @? (S.concat_array ~sep:":" [||] = ""); "empty singleton" @? (S.concat_array ~sep:":" [|""|] = ""); "singleton" @? (S.concat_array ~sep:":" [|"Hello"|] = "Hello"); "Words" @? (S.concat_array ~sep:" " [|"Hello"; "World"; "!"|] = "Hello World !"); ); "suffix" >:: (fun () -> let base = "0123456789" in let test len res = (sprintf "%d" len) @? (S.suffix base len = res) in test 0 ""; test 1 "9"; test 2 "89"; test 10 base; test 20 base; assert_raises ~msg:"-1" (Invalid_argument "suffix expecting nonnegative argument") (fun () -> test (-1) ""); ); "prefix" >:: (fun () -> let base = "0123456789" in let test len res = (sprintf "%d" len) @? (S.prefix base len = res) in test 0 ""; test 1 "0"; test 2 "01"; test 10 base; test 20 base; assert_raises ~msg:"-1" (Invalid_argument "prefix expecting nonnegative argument") (fun () -> test (-1) ""); ); "drop_suffix" >:: (fun () -> let base = "0123456789" in let test len res = (sprintf "%d" len) @? (S.drop_suffix base len = res) in test 0 base; test 1 "012345678"; test 2 "01234567"; test 10 ""; test 20 ""; assert_raises ~msg:"-1" (Invalid_argument "drop_suffix expecting nonnegative argument") (fun () -> test (-1) ""); ); "drop_prefix" >:: (fun () -> let base = "0123456789" in let test len res = (sprintf "%d" len) @? (S.drop_prefix base len = res) in test 0 base; test 1 "123456789"; test 2 "23456789"; test 10 ""; test 20 ""; assert_raises ~msg:"-1" (Invalid_argument "drop_prefix expecting nonnegative argument") (fun () -> test (-1) ""); ); "chop_suffix_exn" >:: (fun () -> "simple" @? (S.chop_suffix_exn str1 ~suffix:"7890" = "123456"); "end" @? (S.chop_suffix_exn str1 ~suffix:"" = "1234567890"); assert_raises ~msg:"not a suffix" (Invalid_argument "Core_string.chop_suffix_exn \"1234567890\" \"abc\"") (fun () -> S.chop_suffix_exn str1 ~suffix:"abc") ); "chop_prefix_exn" >:: (fun () -> "simple" @? (S.chop_prefix_exn str1 ~prefix:"123" = "4567890"); "end" @? (S.chop_prefix_exn str1 ~prefix:"" = "1234567890"); assert_raises ~msg:"not a prefix" (Invalid_argument "Core_string.chop_prefix_exn \"1234567890\" \"abc\"") (fun () -> S.chop_prefix_exn str1 ~prefix:"abc") ); "chop_suffix" >:: (fun () -> "simple" @? (S.chop_suffix str1 ~suffix:"7890" = Some "123456"); "end" @? (S.chop_suffix str1 ~suffix:"" = Some "1234567890"); "not a suffix" @? (S.chop_suffix str1 ~suffix:"abc" = None) ); "chop_prefix" >:: (fun () -> "simple" @? (S.chop_prefix str1 ~prefix:"123" = Some "4567890"); "end" @? (S.chop_prefix str1 ~prefix:"" = Some "1234567890"); "not a prefix" @? (S.chop_prefix str1 ~prefix:"abc" = None) ); "to_list_and_to_list_rev" >:: (fun () -> let seaweed = "bladderwrack" in assert (S.to_list seaweed = ['b';'l';'a';'d';'d';'e';'r';'w';'r';'a';'c';'k']); assert (S.to_list_rev seaweed = ['k';'c';'a';'r';'w';'r';'e';'d';'d';'a';'l';'b']); let empty = "" in assert (S.to_list empty = []); assert (S.to_list_rev empty = []) ); ("mem" >::: [ ("default" >:: fun () -> let test t c b = (sprintf "%c in %s = %b" c t b) @? (S.mem t c = b) in (let t = "abc" in test t 'a' true; test t 'b' true; test t 'c' true; test t 'x' false); (let t = "ab" in test t 'a' true; test t 'b' true; test t 'x' false); (let t = "a" in test t 'a' true; test t 'x' false); (let t = "" in test t 'x' false); ); ("equals-is-always-true" >:: fun () -> let equal (_ : char) (_ : char) = true in let test t c b = (sprintf "%c in %s = %b" c t b) @? (S.mem ~equal t c = b) in (let t = "abc" in test t 'a' true; test t 'b' true; test t 'c' true; test t 'x' true); (let t = "ab" in test t 'a' true; test t 'x' true); (let t = "a" in test t 'a' true; test t 'x' true); (let t = "" in test t 'x' false); ); ("equals-is-always-false" >:: fun () -> let equal (_ : char) (_ : char) = false in let test t c = (sprintf "%c in %s = false" c t) @? (not (S.mem ~equal t c)) in (let t = "abc" in test t 'a'; test t 'b'; test t 'c'; test t 'x'); (let t = "ab" in test t 'a'; test t 'x'); (let t = "a" in test t 'a'; test t 'x'); (let t = "" in test t 'x'); ); ("equals-is-strange" >:: fun () -> let equal c1 c2 = c1 = c2 || c1 = 'U' || c2 = 'U' in let test t c b = (sprintf "%c in %s = %b" c t b) @? (S.mem ~equal t c = b) in (let t = "abc" in test t 'a' true; test t 'b' true; test t 'c' true; test t 'x' false; test t 'U' true); (let t = "ab" in test t 'a' true; test t 'x' false; test t 'U' true); (let t = "a" in test t 'a' true; test t 'x' false; test t 'U' true); (let t = "" in test t 'x' false; test t 'U' false); (let t = "U" in test t 'a' true; test t 'x' true; test t 'U' true); ); ]); ] core-113.00.00/test/core_unix_test.ml000066400000000000000000000020701256461075500173210ustar00rootroot00000000000000open Core.Std open OUnit open Unix let with_large_file f = let filename = Filename.temp_file "large" "test" in protect ~f:(fun () -> ignore (system (sprintf "dd if=/dev/zero of=%s bs=1 count=1 seek=$(echo '2 ^ 32 + 1' | bc -l) > /dev/null 2>/dev/null" filename)); ignore (f filename)) ~finally:(fun () -> Sys.remove filename); true let test = "core_unix" >::: [ "stat" >:: (fun () -> "stat-large" @? with_large_file (fun fn -> stat fn); "lstat-large" @? with_large_file (fun fn -> lstat fn)); "mcast_sockopts" >:: (fun () -> let sock = Unix.socket ~domain:Unix.PF_INET ~kind:Unix.SOCK_DGRAM ~protocol:0 in Unix.set_mcast_ttl sock 2; assert ((Unix.get_mcast_ttl sock) = 2); Unix.set_mcast_ttl sock 4; assert ((Unix.get_mcast_ttl sock) = 4); Unix.set_mcast_loop sock true; assert (Unix.get_mcast_loop sock); Unix.set_mcast_loop sock false; assert (not (Unix.get_mcast_loop sock)); Unix.close sock); ] core-113.00.00/test/crc_test.ml000066400000000000000000000005511256461075500160770ustar00rootroot00000000000000open OUnit;; open Core.Std let test = "crc" >::: begin [ "crc32" >:: (fun () -> "consistent" @? (Crc.crc32 "foo bar baz" = Crc.crc32 "foo bar baz"); ); "crc32hex" >:: (fun () -> "consistent" @? (Crc.crc32hex "baz quux" = Crc.crc32hex "baz quux"); ); ] end core-113.00.00/test/doubly_linked_test.ml000066400000000000000000000764131256461075500201660ustar00rootroot00000000000000open OUnit open Core.Std module type S = sig val name : string module Elt : sig type 'a t val value : 'a t -> 'a val equal : 'a t -> 'a t -> bool val sexp_of_t : ('a -> Sexp.t) -> 'a t -> Sexp.t end type 'a t include Container.S1 with type 'a t := 'a t include Sexpable.S1 with type 'a t := 'a t val invariant : 'a t -> unit val create : unit -> 'a t val of_list : 'a list -> 'a t val equal : 'a t -> 'a t -> bool val is_first : 'a t -> 'a Elt.t -> bool val is_last : 'a t -> 'a Elt.t -> bool val first_elt : 'a t -> 'a Elt.t option val last_elt : 'a t -> 'a Elt.t option val first : 'a t -> 'a option val last : 'a t -> 'a option val next : 'a t -> 'a Elt.t -> 'a Elt.t option val prev : 'a t -> 'a Elt.t -> 'a Elt.t option val insert_before : 'a t -> 'a Elt.t -> 'a -> 'a Elt.t val insert_after : 'a t -> 'a Elt.t -> 'a -> 'a Elt.t val insert_first : 'a t -> 'a -> 'a Elt.t val insert_last : 'a t -> 'a -> 'a Elt.t val remove : 'a t -> 'a Elt.t -> unit val remove_first : 'a t -> 'a option val remove_last : 'a t -> 'a option val find_elt : 'a t -> f:('a -> bool) -> 'a Elt.t option val clear : 'a t -> unit val copy : 'a t -> 'a t val transfer : src:'a t -> dst:'a t -> unit val filter_inplace : 'a t -> f:('a -> bool) -> unit end module Hero : S = struct let name = "hero" include Doubly_linked end module Foil : S = struct let name = "foil" type 'a t = { mutable elts : 'a elt list; mutable num_readers : int; } and 'a elt = { value : 'a; mutable root : 'a t } module Elt = struct type 'a t = 'a elt let equal (t1 : _ t) t2 = phys_equal t1 t2 let value t = t.value let sexp_of_t sexp_of_a t = sexp_of_a t.value end let to_list t = List.map ~f:Elt.value t.elts let of_list xs = let t = { elts = []; num_readers = 0 } in t.elts <- List.map xs ~f:(fun x -> {value = x; root = t}); t let length t = List.length (to_list t) let is_empty t = List.is_empty (to_list t) let to_array t = List.to_array (to_list t) let read_wrap t f = t.num_readers <- t.num_readers + 1; Exn.protect ~f ~finally:(fun () -> t.num_readers <- t.num_readers - 1) let for_all t ~f = read_wrap t (fun () -> List.for_all (to_list t) ~f) let exists t ~f = read_wrap t (fun () -> List.exists (to_list t) ~f) let find t ~f = read_wrap t (fun () -> List.find (to_list t) ~f) let find_map t ~f = read_wrap t (fun () -> List.find_map (to_list t) ~f) let iter t ~f = read_wrap t (fun () -> List.iter (to_list t) ~f) let fold t ~init ~f = read_wrap t (fun () -> List.fold (to_list t) ~init ~f) let count t ~f = read_wrap t (fun () -> List.count (to_list t) ~f) let sum m t ~f = read_wrap t (fun () -> List.sum m (to_list t) ~f) let mem ?equal t a = read_wrap t (fun () -> List.mem ?equal (to_list t) a) let min_elt t ~cmp = read_wrap t (fun () -> List.min_elt ~cmp (to_list t)) let max_elt t ~cmp = read_wrap t (fun () -> List.max_elt ~cmp (to_list t)) let sexp_of_t sexp_of_a t = List.sexp_of_t sexp_of_a (to_list t) let t_of_sexp a_of_sexp s = of_list (List.t_of_sexp a_of_sexp s) let invariant _ = () let equal t1 t2 = phys_equal t1 t2 let create () = of_list [] let assert_no_pending_readers t = assert (t.num_readers = 0) let filter_inplace t ~f = assert_no_pending_readers t; t.elts <- List.filter t.elts ~f:(fun e -> f e.value) let copy t = of_list (to_list t) let clear t = assert_no_pending_readers t; let dummy = create () in List.iter t.elts ~f:(fun e -> e.root <- dummy); t.elts <- [] let find_elt t ~f = List.find t.elts ~f:(fun elt -> f elt.value) let first_elt t = List.hd t.elts let last_elt t = List.last t.elts let is_last t e = assert (equal t e.root); match last_elt t with | None -> assert false | Some e' -> Elt.equal e e' let is_first t e = assert (equal t e.root); match first_elt t with | None -> assert false | Some e' -> Elt.equal e e' let first t = Option.map ~f:Elt.value (first_elt t) let last t = Option.map ~f:Elt.value (last_elt t) type 'a zipper = { before : 'a elt list; cursor : 'a elt; after : 'a elt list; } let elts_to_zipper = function | [] -> None | hd :: tl -> Some { before = []; cursor = hd; after = tl } let elts_of_zipper z = List.rev_append z.before (z.cursor :: z.after) let search z e = let rec loop ({before; cursor = this; after} as z) = if Elt.equal e this then Some z else match after with | [] -> None | next :: rest -> loop { before = this :: before; cursor = next; after = rest } in loop z let search_to t e = assert (equal t e.root); match elts_to_zipper t.elts with | None -> failwith "wrong list" | Some z -> match search z e with | None -> failwith "wrong list" | Some z -> z let neighbor before_or_after t e = let z = search_to t e in let side = match before_or_after with | `Before -> z.before | `After -> z.after in List.hd side let next t e = neighbor `After t e let prev t e = neighbor `Before t e let insert_neighbor before_or_after t e x = let z = search_to t e in let new_elt = { value = x; root = t } in let z = match before_or_after with | `Before -> { z with before = new_elt :: z.before } | `After -> { z with after = new_elt :: z.after } in assert_no_pending_readers t; t.elts <- elts_of_zipper z; new_elt let insert_before t elt x = insert_neighbor `Before t elt x let insert_after t elt x = insert_neighbor `After t elt x let insert_first t x = assert_no_pending_readers t; let new_elt = { value = x; root = t } in t.elts <- new_elt :: t.elts; new_elt let insert_last t x = assert_no_pending_readers t; let new_elt = { value = x; root = t } in t.elts <- t.elts @ [new_elt]; new_elt let remove t e = let z = search_to t e in assert_no_pending_readers t; e.root <- create (); t.elts <- begin match z.before with | [] -> z.after | hd :: tl -> elts_of_zipper {z with before = tl; cursor = hd } end let remove_first t = Option.map (first_elt t) ~f:(fun elt -> remove t elt; Elt.value elt) let remove_last t = Option.map (last_elt t) ~f:(fun elt -> remove t elt; Elt.value elt) let transfer ~src ~dst = assert (not (equal src dst)); List.iter src.elts ~f:(fun e -> e.root <- dst); dst.elts <- dst.elts @ src.elts; src.elts <- [] end exception Both_raised module Both : S = struct module M : sig type ('a1, 'a2) m val ( *@ ) : ('a1 -> 'b1, 'a2 -> 'b2) m -> ('a1, 'a2) m -> ('b1, 'b2) m val pure : 'a -> ('a, 'a) m val pair : 'a -> 'b -> ('a, 'b) m val opt_obs : ('a option, 'b option) m -> ('a, 'b) m option (* observe option *) val obs : ('a, 'a) m -> 'a (* observe *) end = struct type ('a, 'b) m = ('a, exn) Result.t * ('b, exn) Result.t let app f x = match f with | Error e -> Error e | Ok f -> match x with | Error e -> Error e | Ok x -> try Ok (f x) with e -> Error e let ( *@ ) (f, g) (x, y) = (app f x, app g y) let pair x y = (Ok x, Ok y) let pure x = pair x x let force = function | (Ok x, Ok y ) -> (x, y) | (Error _, Error _) -> raise Both_raised | (Error _, Ok _ ) -> failwith "hero failure =/= foil success" | (Ok _, Error _) -> failwith "hero success =/= foil failure" let obs t = let (x, y) = force t in assert (x = y); x let opt_obs t = match force t with | (Some x, Some y) -> Some (Ok x, Ok y) | (None, None) -> None | (Some _, None) -> failwith "hero some =/= foil none" | (None, Some _) -> failwith "hero none =/= foil some" end open M let name = "both" type 'a t = ('a Hero.t, 'a Foil.t) m module Elt = struct type 'a t = ('a Hero.Elt.t, 'a Foil.Elt.t) m let value t = obs (pair Hero.Elt.value Foil.Elt.value *@ t) let sexp_of_t sexp_of_a t = obs (pair Hero.Elt.sexp_of_t Foil.Elt.sexp_of_t *@ pure sexp_of_a *@ t) let equal t1 t2 = obs (pair Hero.Elt.equal Foil.Elt.equal *@ t1 *@ t2) end let sexp_of_t sexp_of_a t = obs (pair Hero.sexp_of_t Foil.sexp_of_t *@ pure sexp_of_a *@ t) let t_of_sexp a_of_sexp s = pair Hero.t_of_sexp Foil.t_of_sexp *@ pure a_of_sexp *@ pure s let exists t ~f = obs (pair (Hero.exists ~f) (Foil.exists ~f) *@ t) let mem ?equal t a = obs (pair (fun h -> Hero.mem ?equal h a) (fun f -> Foil.mem ?equal f a) *@ t) ;; let find_map t ~f = obs (pair (Hero.find_map ~f) (Foil.find_map ~f) *@ t) let find t ~f = obs (pair (Hero.find ~f) (Foil.find ~f) *@ t) let for_all t ~f = obs (pair (Hero.for_all ~f) (Foil.for_all ~f) *@ t) let is_empty t = obs (pair Hero.is_empty Foil.is_empty *@ t) let length t = obs (pair Hero.length Foil.length *@ t) let of_list xs = pair Hero.of_list Foil.of_list *@ pure xs let to_list t = obs (pair Hero.to_list Foil.to_list *@ t) let to_array t = obs (pair Hero.to_array Foil.to_array *@ t) let min_elt t ~cmp = obs (pair (Hero.min_elt ~cmp) (Foil.min_elt ~cmp) *@ t) let max_elt t ~cmp = obs (pair (Hero.max_elt ~cmp) (Foil.max_elt ~cmp) *@ t) (* punt: so as not to duplicate any effects in passed-in functions *) let fold _ = failwith "unimplemented" let iter _ = failwith "unimplemented" let count _ = failwith "unimplemented" let sum _ = failwith "unimplemented" let invariant t = obs (pair Hero.invariant Foil.invariant *@ t) let create () = pair Hero.create Foil.create *@ pure () let equal t1 t2 = obs (pair Hero.equal Foil.equal *@ t1 *@ t2) let is_first t elt = obs (pair Hero.is_first Foil.is_first *@ t *@ elt) let is_last t elt = obs (pair Hero.is_last Foil.is_last *@ t *@ elt) let first_elt t = opt_obs (pair Hero.first_elt Foil.first_elt *@ t) let last_elt t = opt_obs (pair Hero.last_elt Foil.last_elt *@ t) let first t = obs (pair Hero.first Foil.first *@ t) let last t = obs (pair Hero.last Foil.last *@ t) let next t elt = opt_obs (pair Hero.next Foil.next *@ t *@ elt) let prev t elt = opt_obs (pair Hero.prev Foil.prev *@ t *@ elt) let insert_before t elt v = pair Hero.insert_before Foil.insert_before *@ t *@ elt *@ pure v let insert_after t elt v = pair Hero.insert_after Foil.insert_after *@ t *@ elt *@ pure v let insert_first t v = pair Hero.insert_first Foil.insert_first *@ t *@ pure v let insert_last t v = pair Hero.insert_last Foil.insert_last *@ t *@ pure v let remove t elt = obs (pair Hero.remove Foil.remove *@ t *@ elt) let remove_first t = obs (pair Hero.remove_first Foil.remove_first *@ t) let remove_last t = obs (pair Hero.remove_last Foil.remove_last *@ t) let clear t = obs (pair Hero.clear Foil.clear *@ t) let copy t = pair Hero.copy Foil.copy *@ t let find_elt t ~f = opt_obs (pair (Hero.find_elt ~f) (Foil.find_elt ~f) *@ t) let filter_inplace t ~f = obs (pair (Hero.filter_inplace ~f) (Foil.filter_inplace ~f) *@ t) let transfer ~src ~dst = obs (pair (fun src dst -> Hero.transfer ~src ~dst) (fun src dst -> Foil.transfer ~src ~dst) *@ src *@ dst) end module Make_test (X : S) = struct open X exception Finished let assert_raises f = try f (); raise Finished with | Finished -> assert false | _ -> () module Help = struct let of_sexp s = t_of_sexp Int.t_of_sexp (Sexp.of_string s) let even n = (n mod 2 = 0) end let test = X.name >::: [ "empty" >:: (fun () -> let t = create () in assert (length t = 0); assert (is_empty t); assert (first_elt t = None); assert (last_elt t = None); assert (first t = None); assert (last t = None); assert (remove_first t = None); assert (remove_last t = None); assert (to_list t = []) ); "single" >:: (fun () -> let t = create () in let elt = insert_first t 13 in assert (length t = 1); assert (not (is_empty t)); assert (first t = Some 13); assert (last t = Some 13); assert (to_list t = [13]); assert (is_first t elt); assert (is_last t elt); ); "pair" >:: (fun () -> let t = create () in let elt2 = insert_first t 14 in let elt1 = insert_first t 13 in assert (length t = 2); assert (not (is_empty t)); assert true; assert (first t = Some 13); assert (last t = Some 14); assert (to_list t = [13; 14]); assert (is_first t elt1); assert (is_last t elt2); ); "container" >:: (fun () -> let module T = Container_test.Test_S1 (X) in T.test (); ); "of_list" >:: (fun () -> for i = 0 to 5 do let l = List.init i ~f:ident in let t = of_list l in assert (l = to_list t); done ); "clear" >:: (fun () -> for i = 0 to 5 do let t = of_list (List.init i ~f:ident) in clear t; assert (is_empty t) done); "transfer" >:: (fun () -> for i1 = 0 to 3 do let l1 = List.init i1 ~f:ident in for i2 = 0 to 3 do let l2 = List.init i2 ~f:ident in let t1 = of_list l1 in let t2 = of_list l2 in transfer ~src:t1 ~dst:t2; assert (is_empty t1); assert (to_list t2 = l2 @ l1); done done ); "transfer2" >:: (fun () -> let l1 = create () in let e = insert_first l1 9 in let l2 = create () in transfer ~src:l1 ~dst:l2; remove l2 e; assert (is_empty l1); assert (is_empty l2); ); "insert-remove" >:: (fun () -> let t = create () in let is_elts elts = assert (to_list t = List.map elts ~f:Elt.value); let rec loop elt elts = match (elt, elts) with | (None, []) -> () | (Some elt, elt' :: elts) -> assert (Elt.equal elt elt'); loop (next t elt) elts | _ -> assert false in loop (first_elt t) elts; begin match elts with | [] -> () | elt :: elts -> assert (prev t elt = None); assert (is_first t elt); assert (Option.equal Elt.equal (first_elt t) (Some elt)); List.iter elts ~f:(fun elt -> assert (not (is_first t elt))); ignore (List.fold elts ~init:elt ~f:(fun prev elt -> assert (Option.equal Elt.equal (X.prev t elt) (Some prev)); elt)); end; begin match List.rev elts with | [] -> () | elt :: elts -> assert (next t elt = None); assert (is_last t elt); assert (Option.equal Elt.equal (last_elt t) (Some elt)); List.iter elts ~f:(fun elt -> assert (not (is_last t elt))); ignore (List.fold elts ~init:elt ~f:(fun next elt -> assert (Option.equal Elt.equal (X.next t elt) (Some next)); elt)) end in let elt1 = insert_first t () in is_elts [elt1]; let elt2 = insert_first t () in is_elts [elt2; elt1]; let elt3 = insert_last t () in is_elts [elt2; elt1; elt3]; remove t elt1; is_elts [elt2; elt3]; let elt4 = insert_after t elt2 () in is_elts [elt2; elt4; elt3]; let elt5 = insert_before t elt2 () in is_elts [elt5; elt2; elt4; elt3]; ignore (remove_last t); is_elts [elt5; elt2; elt4]; ignore (remove_first t); is_elts [elt2; elt4]; ignore (remove_first t); is_elts [elt4]; ignore (remove_first t); is_elts []; ); "filter-inplace" >:: (fun () -> let t = create () in let r1 = ref 0 in let r2 = ref 1 in let r3 = ref 2 in let i x = ignore (insert_first t x) in i r1; i r2; i r3; assert (length t = 3); filter_inplace t ~f:(fun r -> not (phys_equal r r2)); assert (length t = 2); let len = fold t ~init:0 ~f:(fun acc x -> assert (not (phys_equal x r2)); acc + 1) in assert (len = length t) ); "wrong-list-1" >:: (fun () -> let t1 = create () in let t2 = create () in let e1 = insert_first t1 0 in (try ignore (remove t2 e1); assert false with _ -> ()); ); "wrong-list-2" >:: (fun () -> let t4 = create () in let t5 = t_of_sexp Int.t_of_sexp (Sexp.of_string "(1 2)") in match last_elt t5 with | None -> assert false | Some e6 -> try ignore (prev t4 e6); raise Exit with | Exit -> assert false | _ -> () ); "transfer-self" >:: (fun () -> let l2 = of_list [] in try transfer ~src:l2 ~dst:l2; raise Exit with | Exit -> assert false | _ -> () ); "write-lock" >::: [ "remove" >:: (fun () -> let xs = [1; 2; 3] in let t = of_list xs in let e = Option.value_exn (first_elt t) in iter t ~f:(fun _ -> assert_raises (fun () -> ignore (remove_first t))); assert (to_list t = xs); iter t ~f:(fun _ -> assert_raises (fun () -> ignore (remove_last t))); assert (to_list t = xs); iter t ~f:(fun _ -> assert_raises (fun () -> ignore (remove t e))); assert (to_list t = xs) ); "insert" >:: (fun () -> let xs = [1; 2; 3] in let t = of_list xs in let e = Option.value_exn (first_elt t) in iter t ~f:(fun _ -> assert_raises (fun () -> ignore (insert_first t 4))); assert (to_list t = xs); iter t ~f:(fun _ -> assert_raises (fun () -> ignore (insert_last t 5))); assert (to_list t = xs); iter t ~f:(fun _ -> assert_raises (fun () -> ignore (insert_before t e 6))); assert (to_list t = xs); iter t ~f:(fun _ -> assert_raises (fun () -> ignore (insert_after t e 7))); assert (to_list t = xs) ); ]; "transfer2" >:: (fun () -> let open Help in let src = of_sexp "(1)" in ignore src; let elt = insert_last src 4 in ignore elt; let dst = of_sexp "(1 2 3 4)" in ignore dst; transfer ~src ~dst; ignore (next dst elt); () ); "counterexample1" >:: (fun () -> let open Help in let l = of_sexp "(1)" in let e = insert_first l 2 in invariant l; assert (Option.is_some (remove_first l)); assert_raises (fun () -> ignore (is_last l e)); () ); "counterexample2" >:: (fun () -> let l = of_list [1] in let e = insert_first l 3 in invariant l; ignore (remove l e); invariant l; assert (Option.is_some (first_elt l)) ); "counterexample3" >:: (fun () -> let open Help in let l1 = of_sexp "(1 2 3)" in let l2 = copy l1 in transfer ~src:l2 ~dst:l1; invariant l1; ); "counterexample4" >:: (fun () -> let open Help in let l1 = of_sexp "(1 2 3 4)" in assert (length l1 = 4); let _ = insert_last l1 4 in assert (length l1 = 5); let l2 = of_list [1; 2; 3] in assert (length l2 = 3); transfer ~src:l1 ~dst:l2; match (length l1, length l2) with | (0, 8) -> () | (len1, len2) -> failwithf "%s: len1 = %d =/= 0; len2 = %d =/= 8" X.name len1 len2 () ); ] end module Bisimulation = struct module Random = struct let prng = Random.State.make [|3; 1; 4; 1; 5; 9; 2; 6; 5; 3; 5; 8; 9; 7; 9; 3; 2; 3; 8; 4; 6; 2; 6; 4; 3; 3; 8; 3; 2; 7; 9; 5; 0; 2; 8; 8; 4; 1; 9; 7; 1; 6; 9; 3; 9; 9; 3; 7; 5; 1; 0; 5; 8; 2; 0; 9; 7; 4; 9; 4; 4; 5; 9; 2; 3; 0; 7; 8; 1; 6; 4; 0; 6; 2; 8; 6; 2; 0; 8; 9; 9; 8; 6; 2; 8; 0; 3; 4; 8; 2; 5; 3; 4; 2; 1; 1; 7; 0; 6; 7; 9; 8; 2; 1; 4; 8; 0; 8; 6; 5; 1; 3; 2; 8; 2; 3; 0; 6; 6; 4; 7; 0; 9; 3; 8; 4; 4; 6; 0; 9; 5; 5; 0; 5; 8; 2; 2; 3; 1; 7; 2; 5; 3; 5; 9; 4; 0; 8; 1; 2; 8; 4; 8; 1; 1; 1; 7; 4; 5; 0; 2; 8; 4; 1; 0; 2; 7; 0; 1; 9; 3; 8; 5; 2; 1; 1; 0; 5; 5; 5; 9; 6; 4; 4; 6; 2; 2; 9; 4; 8; 9; 5; 4; 9; 3; 0; 3; 8; 1; 9; 6; 4; 4; 2; 8; 8; 1; 0; 9; 7; 5; 6; 6; 5; 9; 3; 3; 4; 4; 6; 1; 2; 8; 4; 7; 5; 6; 4; 8; 2; 3; 3; 7; 8; 6; 7; 8; 3; 1; 6; 5; 2; 7; 1; 2; 0; 1; 9; 0; 9; 1; 4; 5; 6; 4; 8; 5; 6; 6; 9; 2; 3; 4; 6; 0; 3; 4; 8; 6; 1; 0; 4; 5; 4; 3; 2; 6; 6; 4; 8; 2; 1; 3; 3; 9; 3; 6; 0; 7; 2; 6; 0; 2; 4; 9; 1; 4; 1; 2; 7; 3; 7; 2; 4; 5; 8; 7; 0; 0; 6; 6; 0; 6; 3; 1; 5; 5; 8; 8; 1; 7; 4; 8; 8; 1; 5; 2; 0; 9; 2; 0; 9; 6; 2; 8; 2; 9; 2; 5; 4; 0; 9; 1; 7; 1; 5; 3; 6; 4; 3; 6; 7; 8; 9; 2; 5; 9; 0; 3; 6; 0; 0; 1; 1; 3; 3; 0; 5; 3; 0; 5; 4; 8; 8; 2; 0; 4; 6; 6; 5; 2; 1; 3; 8; 4; 1; 4; 6; 9; 5; 1; 9; 4; 1; 5; 1; 1; 6; 0; 9; 4; 3; 3; 0; 5; 7; 2; 7; 0; 3; 6; 5; 7; 5; 9; 5; 9; 1; 9; 5; 3; 0; 9; 2; 1; 8; 6; 1; 1; 7; 3; 8; 1; 9; 3; 2; 6; 1; 1; 7; 9; 3; 1; 0; 5; 1; 1; 8; 5; 4; 8; 0; 7; 4; 4; 6; 2; 3; 7; 9; 9; 6; 2; 7; 4; 9; 5; 6; 7; 3; 5; 1; 8; 8; 5; 7; 5; 2; 7; 2; 4; 8; 9; 1; 2; 2; 7; 9; 3; 8; 1; 8; 3; 0; 1; 1; 9; 4; 9; 1; 2; 9; 8; 3; 3; 6; 7; 3; 3; 6; 2; 4; 4; 0; 6; 5; 6; 6; 4; 3; 0; 8; 6; 0; |] let int n = Random.State.int prng n let bool () = Random.State.bool prng end module Uid = Unique_id.Int () type v = int with sexp type l = Uid.t * v Both.t type e = Uid.t * v Both.Elt.t let sexp_of_l (id, _) = Sexp.Atom ("l" ^ Uid.to_string id) let sexp_of_e (id, _) = Sexp.Atom ("e" ^ Uid.to_string id) type p = Even | Odd with sexp_of module F = struct type t = | Clear of l | Copy of l | Create | Elt_equal of e * e | Elt_sexp of e | Elt_value of e | Equal of l * l | Exists of l * p | Filter_inplace of l * p | Find_elt of l * p | Find of l * p | First_elt of l | First of l | For_all of l * p | Insert_after of l * e * v | Insert_before of l * e * v | Insert_first of l * v | Insert_last of l * v | Invariant of l | Is_empty of l | Is_first of l * e | Is_last of l * e | Last_elt of l | Last of l | Length of l | Next of l * e | Of_list of v list | Of_sexp of Sexp.t | Prev of l * e | Remove_first of l | Remove_last of l | Remove of l * e | To_array of l | To_list of l | To_sexp of l | Transfer of l * l with sexp_of, variants end open F type f = F.t with sexp_of type env = { ls : (Uid.t, l) Hashtbl.t; es : (Uid.t, e) Hashtbl.t; } let values = List.range 1 6 let lists = List.map (List.range 0 6) ~f:(fun n -> (List.take values n)) let sexps = List.map lists ~f:(List.sexp_of_t Int.sexp_of_t) let values = List.to_array values let lists = List.to_array lists let sexps = List.to_array sexps exception Skip with sexp let array_rand arr = try let n = Array.length arr in arr.(Random.int n) with _ -> raise Skip (* sometimes we try to select from a not-yet-non-empty array *) let hashtbl_rand h = let arr = List.to_array (Hashtbl.to_alist h) in snd (array_rand arr) let rand_p _env = if Random.bool () then Even else Odd let rand_v _env = array_rand values let rand_vs _env = array_rand lists let rand_s _env = array_rand sexps let rand_e env = hashtbl_rand env.es let rand_l env = hashtbl_rand env.ls let rand_f = let tbl = lazy begin let count = ref 0 in let h = Hashtbl.Poly.create ~size:50 () in let v of_env _ = Hashtbl.set h ~key:(incr count; !count) ~data:of_env in Variants.iter ~clear: (v(fun env -> Clear (rand_l env))) ~copy: (v(fun env -> Copy (rand_l env))) ~create: (v(fun _env -> Create)) ~elt_equal: (v(fun env -> Elt_equal (rand_e env, rand_e env))) ~elt_sexp: (v(fun env -> Elt_sexp (rand_e env))) ~elt_value: (v(fun env -> Elt_value (rand_e env))) ~equal: (v(fun env -> Equal (rand_l env, rand_l env))) ~exists: (v(fun env -> Exists (rand_l env, rand_p env))) ~filter_inplace:(v(fun env -> Filter_inplace (rand_l env, rand_p env))) ~find_elt: (v(fun env -> Find_elt (rand_l env, rand_p env))) ~find: (v(fun env -> Find (rand_l env, rand_p env))) ~first_elt: (v(fun env -> First_elt (rand_l env))) ~first: (v(fun env -> First (rand_l env))) ~for_all: (v(fun env -> For_all (rand_l env, rand_p env))) ~insert_after: (v(fun env -> Insert_after (rand_l env, rand_e env, rand_v env))) ~insert_before: (v(fun env -> Insert_before (rand_l env, rand_e env, rand_v env))) ~insert_first: (v(fun env -> Insert_first (rand_l env, rand_v env))) ~insert_last: (v(fun env -> Insert_last (rand_l env, rand_v env))) ~invariant: (v(fun env -> Invariant (rand_l env))) ~is_empty: (v(fun env -> Is_empty (rand_l env))) ~is_first: (v(fun env -> Is_first (rand_l env, rand_e env))) ~is_last: (v(fun env -> Is_last (rand_l env, rand_e env))) ~last_elt: (v(fun env -> Last_elt (rand_l env))) ~last: (v(fun env -> Last (rand_l env))) ~length: (v(fun env -> Length (rand_l env))) ~next: (v(fun env -> Next (rand_l env, rand_e env))) ~of_list: (v(fun env -> Of_list (rand_vs env))) ~of_sexp: (v(fun env -> Of_sexp (rand_s env))) ~prev: (v(fun env -> Prev (rand_l env, rand_e env))) ~remove_first: (v(fun env -> Remove_first (rand_l env))) ~remove_last: (v(fun env -> Remove_last (rand_l env))) ~remove: (v(fun env -> Remove (rand_l env, rand_e env))) ~to_array: (v(fun env -> To_array (rand_l env))) ~to_list: (v(fun env -> To_list (rand_l env))) ~to_sexp: (v(fun env -> To_sexp (rand_l env))) ~transfer: (v(fun env -> Transfer (rand_l env, rand_l env))); h end in fun env -> hashtbl_rand (Lazy.force tbl) env exception Traced of Sexp.t * [ `Operation of f | `New_elt of e | `New_list of l ] list with sexp let simulate nsteps = let env = { ls = Hashtbl.Poly.create ~size:50 (); es = Hashtbl.Poly.create ~size:50 (); } in let add h v = let id = Uid.create () in Hashtbl.set h ~key:id ~data:(id, v); id in let trace = Queue.create () in let add_list l = Queue.enqueue trace (`New_list (add env.ls l, l)) in let add_elt e = Queue.enqueue trace (`New_elt (add env.es e, e)) in let add_elt_opt = function | None -> () | Some e -> add_elt e in let pred = function | Even -> fun n -> n mod 0 = 0 | Odd -> fun n -> n mod 0 = 1 in try for _i = 1 to nsteps do try let f = rand_f env in Queue.enqueue trace (`Operation f); match f with | Clear l -> Both.clear (snd l) | Copy l -> add_list (Both.copy (snd l)) | Create -> add_list (Both.create ()) | Elt_equal (e1, e2) -> ignore (Both.Elt.equal (snd e1) (snd e2)) | Elt_sexp e -> ignore (Both.Elt.sexp_of_t sexp_of_v (snd e)) | Elt_value e -> ignore (Both.Elt.value (snd e)) | Equal (t1, t2) -> ignore (Both.equal (snd t1) (snd t2)) | Exists (t, p) -> ignore (Both.exists (snd t) ~f:(pred p)) | Filter_inplace (t, p) -> ignore (Both.filter_inplace (snd t) ~f:(pred p)) | For_all (t, p) -> ignore (Both.for_all (snd t) ~f:(pred p)) | Find_elt (t, p) -> add_elt_opt (Both.find_elt (snd t) ~f:(pred p)) | Find (t, p) -> ignore (Both.find (snd t) ~f:(pred p)) | First_elt t -> add_elt_opt (Both.first_elt (snd t)) | First t -> ignore (Both.first (snd t)) | Insert_after (t, e, v) -> add_elt (Both.insert_after (snd t) (snd e) v) | Insert_before (t, e, v) -> add_elt (Both.insert_before (snd t) (snd e) v) | Insert_first (t, v) -> add_elt (Both.insert_first (snd t) v) | Insert_last (t, v) -> add_elt (Both.insert_last (snd t) v) | Invariant t -> Both.invariant (snd t) | Is_empty t -> ignore (Both.is_empty (snd t)) | Is_first (t, e) -> ignore (Both.is_first (snd t) (snd e)) | Is_last (t, e) -> ignore (Both.is_last (snd t) (snd e)) | Last_elt t -> add_elt_opt (Both.last_elt (snd t)) | Last t -> ignore (Both.last (snd t)) | Length t -> ignore (Both.length (snd t)) | Next (t, e) -> ignore (Both.next (snd t) (snd e)) | Prev (t, e) -> ignore (Both.prev (snd t) (snd e)) | Of_list vs -> add_list (Both.of_list vs) | Remove_first t -> ignore (Both.remove_first (snd t)) | Remove_last t -> ignore (Both.remove_last (snd t)) | Remove (t, e) -> ignore (Both.remove (snd t) (snd e)) | To_sexp t -> ignore (Both.sexp_of_t sexp_of_v (snd t)) | To_array t -> ignore (Both.to_array (snd t)) | Of_sexp s -> add_list (Both.t_of_sexp v_of_sexp s) | To_list t -> ignore (Both.to_list (snd t)) | Transfer (t1, t2) -> ignore (Both.transfer ~src:(snd t1) ~dst:(snd t2)) with | Both_raised | Skip -> () done with e -> raise (Traced (Exn.sexp_of_t e, Queue.to_list trace)) let test = "bisimulation" >:: (fun () -> for _i = 1 to 100_000 do simulate 10 done) end module Hero_test = Make_test (Hero) module Foil_test = Make_test (Foil) let test = "doubly_linked" >::: [ Hero_test.test; Foil_test.test; Bisimulation.test; (* uncomment this once it passes *) ] core-113.00.00/test/fdeque_test.ml000066400000000000000000000047431256461075500166100ustar00rootroot00000000000000open Core.Std open OUnit;; open Fdeque let lpush l q = List.fold ~init:q ~f:enqueue_back l let inv = invariant ignore let test = "fdeque" >::: [ "basic" >:: (fun () -> let q0 = lpush [1;2;3;4;5] empty in let _ ,q1 = dequeue_front_exn q0 in let _ ,q2 = dequeue_front_exn q1 in let q3 = enqueue_back q2 0 in inv q0; inv q1; inv q2; inv q3; "len0" @? (length q0 = 5); "len1" @? (length q1 = 4); "len2" @? (length q2 = 3); "len3" @? (length q3 = 4); "q0" @? (to_list q0 = [1;2;3;4;5]); "q1" @? (to_list q1 = [2;3;4;5]); "q2" @? (to_list q2 = [3;4;5]); "q3" @? (to_list q3 = [3;4;5;0]); "peek_front_exn3" @? (peek_front_exn q3 = 3); "peek_back_exn3" @? (peek_back_exn q3 = 0); "drop_front_exn" @? (to_list (drop_front_exn q0) = to_list q1); "notempty3" @? not (is_empty q3); "empty3" @? is_empty (drop_front_exn (drop_front_exn (drop_front_exn (drop_front_exn q3)))); "misc" @? (to_list (lpush [2;3] (drop_front_exn (drop_front_exn (drop_front_exn (drop_front_exn q3))))) = [2;3]); ); "invariants and list bisimulation" >:: (fun () -> let rec drop_last = function | [] -> assert false | [_] -> [] | x::l -> x :: drop_last l in ignore (List.fold (List.range 0 1000) ~init:(empty,[]) ~f:(fun (q,l) i -> let q,l = match Random.int 9 with | 0 | 1 -> enqueue_back q i, l @ [i] | 2 | 3 -> enqueue_front q i, [i] @ l | 4 -> (match dequeue_front q with | None -> q,l | Some (_,q) -> q, List.tl_exn l) | 5 -> (match drop_front_exn q with | q -> q, List.tl_exn l | exception _ -> q,l) | 6 -> (match dequeue_back q with | None -> q,l | Some (_,q) -> q, drop_last l) | 7 -> (match drop_back_exn q with | q -> q, drop_last l | exception _ -> q,l) | 8 -> rev q, List.rev l | _ -> q,l in inv q; assert (List.equal l (to_list q) ~equal:Int.equal); q,l))) ] core-113.00.00/test/float_test.ml000066400000000000000000000007201256461075500164330ustar00rootroot00000000000000open OUnit;; open Core.Std let terse_test = "terse_test" >:: fun () -> let test number expected = assert_equal ~printer:Fn.id expected (Float.Terse.to_string number); let sexp = Float.Terse.sexp_of_t number in assert_equal ~printer:Fn.id expected (Sexp.to_string sexp) in test 0.0123456789 "0.012345679"; test 0.012345 "0.012345"; test 123456789.123 "1.2345679E+08" let test = TestList [ terse_test ] ;; core-113.00.00/test/hash_heap_test.ml000066400000000000000000000045651256461075500172610ustar00rootroot00000000000000open OUnit;; open Core.Std module Hash_heap = Hash_heap.Make(Int) let s = [1;2;3;4;5;6;7;8;9;10;11] let make () = let h = Hash_heap.create Int.compare in List.iter s ~f:(fun i -> match Hash_heap.push h ~key:i ~data:i with | `Ok -> () | `Key_already_present -> assert false); h let z = string_of_int let test = "hash_heap" >::: [ "create, and push" >:: (fun () -> ignore (make ())); "find" >:: (fun () -> let t = make () in List.iter s ~f:(fun i -> z i @? (Hash_heap.find t i = Some i))); "pop and top" >:: (fun () -> let t = make () in List.iter s ~f:(fun i -> ("top" ^ z i) @? (Hash_heap.top t = Some i); ("pop" ^ z i) @? (Hash_heap.pop t = Some i); ("topafter" ^ z i) @? (Hash_heap.top t <> Some i); ("findable" ^ z i) @? (Hash_heap.find t i = None))); "mem" >:: (fun () -> let t = make () in "all" @? (List.for_all s ~f:(Hash_heap.mem t))); "find_pop" >:: (fun () -> let t = make () in List.iter s ~f:(fun i -> ("lookup" ^ z i) @? (Hash_heap.find_pop t i = Some i); ("remove" ^ z i) @? (not (Hash_heap.mem t i)))); "pop_if" >:: (fun () -> let t = make () in "no" @? (Hash_heap.pop_if t (fun i -> i < 0) = None); "still-there" @? (List.for_all s ~f:(Hash_heap.mem t)); "yes" @? (Hash_heap.pop_if t (fun _ -> true) = Some 1); "gone-top" @? (Hash_heap.top t <> Some 1); "gone-mem" @? (not (Hash_heap.mem t 1))); "iter" >:: (fun () -> let t = make () in "match" @? (Set.compare_direct (Set.Poly.of_list s) (let s = ref Set.Poly.empty in Hash_heap.iter t ~f:(fun ~key ~data -> s := Set.add !s key; assert (key = data)); !s) = 0)); "remove" >:: (fun () -> let t = make () in Hash_heap.remove t 2; Hash_heap.remove t 1; "1gone-mem" @? (not (Hash_heap.mem t 1)); "2gone-mem" @? (not (Hash_heap.mem t 2)); "1gone-top" @? (Hash_heap.top t <> Some 1); "2gone-top" @? (Hash_heap.top t <> Some 2)); "replace" >:: (fun () -> let t = make () in Hash_heap.replace t ~key:1 ~data:12; "present" @? (Hash_heap.find t 1 = Some 12); "top" @? (Hash_heap.top t = Some 2)); ] core-113.00.00/test/hash_queue_test.ml000066400000000000000000000077531256461075500174720ustar00rootroot00000000000000open OUnit;; open Core.Std let test = "hash_queue" >::: [ "basic" >:: (fun () -> let module Hq_arg = struct include String let hash (x : t) = Hashtbl.hash x let sexp_of_t = Sexplib.Conv.sexp_of_string let t_of_sexp = Sexplib.Conv.string_of_sexp end in let module Hq = Hash_queue.Make (Hq_arg) in let hq = Hq.create () in let inv () = Hq.invariant hq in (* tests over empty queue *) inv (); assert (Hq.is_empty hq); assert (Hq.dequeue hq = None); assert (try ignore (Hq.dequeue_exn hq); false with _ -> true); assert (Hq.dequeue_with_key hq = None); assert (try ignore (Hq.dequeue_with_key_exn hq); false with _ -> true); Hq.dequeue_all hq ~f:(fun _ -> assert false); assert (Hq.remove hq "foobar" = `No_such_key); assert (try ignore (Hq.remove_exn hq "foobar"); false with | _ -> true); assert (Hq.replace hq "foobar" 0 = `No_such_key); assert (try ignore (Hq.replace_exn hq "foobar" 0); false with | _ -> true); assert ([] = Hq.foldi hq ~init:[] ~f:(fun ac ~key:_ ~data:_ -> () :: ac)); assert ([] = Hq.fold hq ~init:[] ~f:(fun ac _ -> () :: ac)); Hq.iteri hq ~f:(fun ~key:_ ~data:_ -> assert false); (* test with 10 elems *) let n = 10 in for i = 1 to n do assert (Hq.enqueue hq (string_of_int i) i = `Ok); inv (); done; assert (Hq.length hq = n); assert (List.rev (Hq.foldi hq ~init:[] ~f:(fun ac ~key ~data -> (key, data) :: ac)) = List.init n ~f:(fun i -> let i = i + 1 in (string_of_int i, i))); assert (List.rev (Hq.fold hq ~init:[] ~f:(fun ac data -> data :: ac)) = List.init n ~f:(fun i -> i + 1)); Hq.iteri hq ~f:(fun ~key ~data -> assert (key = string_of_int data)); (* test removing the first element from the queue *) let sum = ref 0 in Hq.iter hq ~f:(fun x -> sum := !sum + x); assert (!sum = (n * (n + 1) / 2)); assert (Hq.mem hq "1"); ignore (Hq.dequeue hq); inv (); assert (not (Hq.mem hq "1")); assert (Hq.length hq = n - 1); (* remove the last *) assert (Hq.remove hq (string_of_int n) = `Ok); (* double remove *) assert (Hq.remove hq (string_of_int n) = `No_such_key); inv (); assert (Hq.length hq = n - 2); (* remove everything *) let num = ref 0 in Hq.dequeue_all hq ~f:(fun _ -> num := !num + 1); inv (); assert (!num = n - 2); assert (Hq.is_empty hq); inv (); Hq.clear hq; assert (Hq.is_empty hq); (* add 100 *) for i = 1 to 100 do assert (Hq.enqueue hq (string_of_int i) i = `Ok); done; (* double booking *) assert (Hq.enqueue hq "42" 42 = `Key_already_present); assert (try Hq.enqueue_exn hq "42" 42; false with | _ -> true); assert (Hq.replace hq "1" 42 = `Ok); assert (Hq.lookup hq "1" = Some 42); assert (Hq.lookup_exn hq "1" = 42); assert (Hq.dequeue_with_key hq = Some ("1", 42)); assert (Hq.replace hq "1" 42 = `No_such_key); assert (try Hq.replace_exn hq "1" 42; false with | _ -> true); assert (Hq.lookup hq "1" = None); assert (try ignore (Hq.lookup_exn hq "1"); false with | Not_found -> true | _ -> false); Hq.clear hq; assert (Hq.is_empty hq); let add i = Hq.enqueue_exn hq (Int.to_string i) i in List.iter [1; 2; 3] ~f:add; assert (["1"; "2"; "3" ] = Hq.keys hq); begin try Hq.iter hq ~f:(fun _ -> add 13); assert false with _ -> (); end; begin try Hq.iter hq ~f:(fun _ -> ignore (Hq.remove hq "foo")); assert false with _ -> (); end; ) ] core-113.00.00/test/hashtbl/000077500000000000000000000000001256461075500153635ustar00rootroot00000000000000core-113.00.00/test/hashtbl/hashtbl_fastcache.ml000066400000000000000000000107721256461075500213520ustar00rootroot00000000000000open Core.Std open Core_extended.Std module X = Table_new_intf (* Cache efficient seperate chaining using arrays instead of lists for hashtbl buckets. The idea is that when doing a lookup the entire bucket is in the same cache line, so iterating through it should be very very fast. In reality, caml (and generalized keys), require some indirection in the bucket. Still, the spine should be in the same cache line, meaning that at least we've removed one level of indirection compared to a list. Another (perhaps serious) problem is that in order to avoid adding yet more indirection we must pre allocate the bucket arrays (or be forced to make them an option, and add yet more indirection). This means that the GC must scan them, since they are blocks. If we were willing to use Obj.magic this situation could be significantly improved. *) module T = struct type ('k, 'v) t = { mutable table : ('k * 'v) option array array; mutable array_length: int; mutable length : int; mutable params : X.params; hashable: 'k X.hashable; } let mk_array size = Array.init size ~f:(fun _ -> Array.create ~len:1 None) let create ?(params = X.default_params) hashable = let s = Int.min (Int.max 1 params.X.initial_size) Sys.max_array_length in { table = mk_array s; array_length = s; length = 0; params = params; hashable = hashable; } let invariant _t = () let hashable t = t.hashable let slot t key = t.hashable.X.hash key mod t.array_length let really_add t ~key ~data = let slot = slot t key in let bucket = t.table.(slot) in let bucket_len = Array.length bucket in let added = ref true in let i = ref 0 in while (* find our bucket with no extra function calls! *) (!i < bucket_len && match bucket.(!i) with | None -> false | Some (k, _) -> let c = t.hashable.X.compare k key in if c = 0 then begin added := false; false end else true) do incr i done; if !added then t.length <- t.length + 1; if !i < bucket_len then bucket.(!i) <- Some (key, data) else begin (* we reached the end of the array without finding a suitable bucket, so we must grow the array *) let new_bucket = Array.init (2 * bucket_len) ~f:(fun i -> if i < bucket_len then bucket.(i) else None) in new_bucket.(bucket_len) <- Some (key, data); t.table.(slot) <- new_bucket end let maybe_resize_table t = if t.params.X.grow && t.length > t.array_length * t.params.X.load_factor then begin let new_array_length = t.array_length * t.params.X.load_factor in let new_table = mk_array new_array_length in let old_table = t.table in t.array_length <- new_array_length; t.table <- new_table; t.length <- 0; for i = 0 to Array.length old_table - 1 do Array.iter old_table.(i) ~f:(function | None -> () | Some (key, data) -> really_add t ~key ~data) done end let add t ~key ~data = maybe_resize_table t; really_add t ~key ~data let clear t = for i = 0 to t.array_length do t.table.(i) <- Array.create ~len:3 None done let find_bucket t key = let bucket = t.table.(slot t key) in let bucket_len = Array.length bucket in (* int refs don't hit the write barrier *) let i = ref 0 in (* while loop avoids function calls *) while (!i < bucket_len && match bucket.(!i) with | None -> true | Some (k, _) -> t.hashable.X.compare k key = 0) do incr i done; if !i < bucket_len then Some (!i, bucket) else None let find t key = match find_bucket t key with | None -> None | Some (i, bucket) -> match bucket.(i) with | None -> None | Some (_, v) -> Some v let mem t key = match find_bucket t key with | None -> false | Some _ -> true let remove t key = match find_bucket t key with | None -> () | Some (i, bucket) -> bucket.(i) <- None let get_params t = t.params let set_params t p = t.params <- p let length t = t.length let fold t ~init ~f = Array.fold t.table ~init ~f:(fun init b -> Array.fold b ~init ~f:(fun init x -> match x with | None -> init | Some (key, data) -> f ~key ~data init)) end include X.Make (T) core-113.00.00/test/hashtbl/hashtbl_fastcache.mli000066400000000000000000000000311256461075500215060ustar00rootroot00000000000000include Table_new_intf.S core-113.00.00/test/hashtbl/hashtbl_separate_chaining.ml000066400000000000000000000107111256461075500230660ustar00rootroot00000000000000open Core.Std (* open Core_extended.Std *) module X = Table_new_intf module Bucket = struct (* This saves a word and an indirection vs a list of triples *) type ('k, 'v) t = | Empty | Cons of 'k * 'v * int * ('k, 'v) t let empty = Empty let remove = let rec loop removed compare acc t key = match t with | Empty -> acc | Cons (key', data', hashv', next) -> if compare key key' = 0 then begin removed := true; loop removed compare acc next key end else loop removed compare (Cons (key', data', hashv', next)) acc key in fun t removed compare key -> loop removed compare Empty t key ;; let rec fold bucket ~init ~f = match bucket with | Empty -> init | Cons (key, data, hashv, next) -> fold next ~init:(f ~key ~data ~hashv init) ~f ;; let rec find t compare key = (* INRIA uses this recursion unrolling trick in their implementation, and it actually works (5 - 10 % improvement) *) match t with | Empty -> None | Cons (key', data, _hval, next) -> if compare key key' = 0 then Some data else match next with | Empty -> None | Cons (key', data, _hval, next) -> if compare key key' = 0 then Some data else match next with | Empty -> None | Cons (key', data, _hval, next) -> if compare key key' = 0 then Some data else find next compare key ;; let cons t key data hashv = Cons (key, data, hashv, t) end module T = struct type ('k, 'v) t = { mutable table: ('k, 'v) Bucket.t array; mutable array_length: int; mutable length: int; mutable params: X.params; hashable: 'k X.hashable; } let create ?(params = X.default_params) hashable = let s = Int.min (Int.max 1 params.X.initial_size) Sys.max_array_length in { table = Array.create ~len:s Bucket.empty; array_length = s; length = 0; params = params; hashable = hashable } ;; let rec add t ~key ~data = let hashv = t.hashable.X.hash key in let i = hashv mod t.array_length in let removed = ref false in let bucket = Bucket.remove t.table.(i) removed t.hashable.X.compare key in t.table.(i) <- Bucket.cons bucket key data hashv; if not !removed then t.length <- t.length + 1; if t.params.X.grow && t.length > t.array_length * t.params.X.load_factor then resize t and resize t = let new_size = Int.min (t.array_length * t.params.X.load_factor) Sys.max_array_length in if new_size > t.array_length then begin let old_table = t.table in t.array_length <- new_size; t.table <- Array.create ~len:t.array_length Bucket.empty; let move ~key ~data ~hashv () = let i = hashv mod t.array_length in t.table.(i) <- Bucket.cons t.table.(i) key data hashv in for i = 0 to Array.length old_table - 1 do Bucket.fold old_table.(i) ~init:() ~f:move done end ;; let slot t key = t.hashable.X.hash key mod t.array_length let remove t key = let i = slot t key in let removed = ref false in t.table.(i) <- Bucket.remove t.table.(i) removed t.hashable.X.compare key; if !removed then t.length <- t.length - 1 ;; let find t key = Bucket.find t.table.(slot t key) t.hashable.X.compare key ;; let length t = t.length let clear t = for i = 0 to t.array_length - 1 do t.table.(i) <- Bucket.empty done; t.length <- 0 ;; let fold = (* this is done recursivly to avoid the write barrier in the case that the accumulator is a structured block, Array.fold does this with a for loop and a ref cell, when it is fixed, we can use it. *) let rec loop buckets i len init f = if i < len then loop buckets (i + 1) len (Bucket.fold buckets.(i) ~init ~f) f else init in fun t ~init ~f -> loop t.table 0 t.array_length init (fun ~key ~data ~hashv:_ acc -> f ~key ~data acc) ;; let invariant t = assert ((fold t ~init:0 ~f:(fun ~key:_ ~data:_ l -> l + 1)) = t.length); assert (Array.length t.table = t.array_length); ;; let hashable t = t.hashable let get_params t = t.params let set_params t params = t.params <- params let mem t key = match find t key with | None -> false | Some _ -> true ;; end include X.Make (T) core-113.00.00/test/hashtbl/hashtbl_separate_chaining.mli000066400000000000000000000000311256461075500232310ustar00rootroot00000000000000include Table_new_intf.S core-113.00.00/test/hashtbl/hashtbl_shootout.ml000066400000000000000000000251231256461075500213110ustar00rootroot00000000000000open Jane.Std open Core_extended.Std open Core_experimental.Std module type Test_intf = sig type ('k, 'v) t val create : ?hash:('k -> int) -> int -> ('k, 'v) t val find : ('k, 'v) t -> 'k -> 'v option val fold : ('k, 'v) t -> init:'c -> f:(key:'k -> data:'v -> 'c -> 'c) -> 'c val add : ('k, 'v) t -> key:'k -> data:'v -> ('k, 'v) t end module Of_table_new (T : Table_new_intf.Basic) : Test_intf = struct type ('k, 'v) t = ('k, 'v) T.t let create ?(hash = Table_new_intf.poly.Table_new_intf.hash) size = T.create ~params:(Table_new_intf.size size) { Table_new_intf. hash = hash; compare = Pervasives.compare } let find = T.find let fold = T.fold let add t ~key ~data = T.add t ~key ~data; t end module Of_map (T : Core.Core_map_intf.S2) : Test_intf = struct type ('k, 'v) t = ('k, 'v) T.t let create ?hash _size = let _ = hash in T.empty let find = T.find let fold t ~init ~f = T.fold t ~init ~f let add t ~key ~data = T.add t ~key ~data end module Std_hashtbl : Test_intf = struct module T = Hashtbl.Poly type ('k, 'v) t = ('k, 'v) T.binable let create ?hash size = let _ = hash in T.create ~size () let find = Hashtbl.find let fold = Hashtbl.fold let add t ~key ~data = Hashtbl.set t ~key ~data; t end module Random = struct include Random.State let string t l = let s = String.create l in for i = 0 to l - 1 do s.[i] <- Core.Std.Char.of_int_exn (int t 255) done; s ;; end module Strings = struct type t = { mutable next: int; set: string array; state: Random.t; } let create () = let t = Array.create ~len:1_000_000 "" in (* This will always generate the same sequence of strings. This is important because we want test results to be reproducable *) let s = Random.make [|5|] in for i = 0 to 999_999 do let sz = 1 + Random.int s 20 in let s = Random.string s sz in t.(i) <- s done; { set = t; next = 0; state = s } let next t = if t.next < Array.length t.set then begin let s = t.set.(t.next) in t.next <- t.next + 1; s end else begin t.next <- 0; t.set.(t.next) end let random t = t.set.(Random.int t.state 1_000_000) (* force the processor to read lots of data into it's cache *) let bash_cache t = let z = ref 0 in for i = 0 to 10_000 do z := Core.Std.Char.to_int t.set.(i).[0] done end module Test_data = struct (* designed to cause heap fragmentation *) let s = Random.make [|10|] module Subtest = struct type t = { mutable a: [`R | `M of [`A of string | `B of int]]; b: int; c: float; d: string; mutable e: int option; } let create () = { a = (if Random.bool s then `R else if Random.bool s then `M (`A (String.create 10)) else `M (`B 9)); b = 10; c = Random.float s 10_000.0; d = Random.string s 15; e = Some 50 } end type t = { a: string; b: int; c: float; mutable d: [`Z of string | `X]; e: float * float; f: float; mutable g: Subtest.t option; } let create () = { a = Random.string s 10; b = 10; c = Random.float s 10_000_000.0; d = `Z (Random.string s 14); e = (Random.float s 100_000.0, Random.float s 100_000.0); f = Random.float s 100_000.0; g = Some (Subtest.create ()) } end module Stats = struct type t = { ord : Order_stats.t; rstats : read_write Rstats.t; } let create () = { ord = Order_stats.create (); rstats = Rstats.create () } let clear t = Order_stats.clear t.ord; Rstats.clear t.rstats let add_sample t sample = let sample = Float.max 0.0 sample in Order_stats.add t.ord sample; Rstats.update_in_place t.rstats sample let run t f = let st = Time.now () in let res = f () in let et = Time.now () in let elapsed = Time.diff et st in add_sample t (Time.Span.to_ms elapsed); res let print t = let get_float = function | Error _ -> failwith "Couldn't get float" | Ok f -> f in Printf.printf "%f,%f,%f,%f,%f,%f,%f,%f\n%!" (Rstats.mean t.rstats) (Rstats.max t.rstats) (Rstats.min t.rstats) (Rstats.stdev t.rstats) (get_float (Order_stats.percentile t.ord 0.25)) (get_float (Order_stats.median t.ord)) (get_float (Order_stats.percentile t.ord 0.75)) (get_float (Order_stats.percentile t.ord 0.95)) end module Make (Tbl : Test_intf) = struct let s = Random.make [|15|] let insert samples size n = let rs = Stats.create () in (* There is no better way to fragment the heap than with a map *) let m = ref Map.empty in let rec loop i tbl = if i < n then begin let key = String.copy (Strings.random samples) in let data = Test_data.create () in let tbl = Stats.run rs (fun () -> Tbl.add tbl ~key ~data) in m := Map.add !m ~key ~data; (* poke some nasty little holes *) data.Test_data.g <- Some (Test_data.Subtest.create ()); data.Test_data.d <- `X; Strings.bash_cache samples; loop (i + 1) tbl end else tbl in let tbl = loop 0 (Tbl.create size) in (rs, tbl) let lookup samples tbl = let rs = Stats.create () in for i = 1 to 1_000_000 do let key = Strings.next samples in ignore (Stats.run rs (fun () -> Tbl.find tbl key)); Strings.bash_cache samples; done; rs let worst_case_insert samples = let rs = Stats.create () in let rec loop i tbl = if i < 500_000 then begin let key = String.copy (Strings.random samples) in let data = Test_data.create () in let tbl = Stats.run rs (fun () -> Tbl.add tbl ~key ~data) in loop (i + 1) tbl end else tbl in (rs, loop 0 (Tbl.create ~hash:(fun _ -> 1) 250_000)) let worst_case_lookup samples tbl = let rs = Stats.create () in for i = 1 to 1_000_000 do let key = Strings.next samples in ignore (Stats.run rs (fun () -> Tbl.find tbl key)); Strings.bash_cache samples; done; rs let memory_overhead samples size n = let rec loop i tbl = if i < n then loop (i + 1) (Tbl.add tbl ~key:(Strings.random samples) ~data:()) else tbl in let tbl = loop 0 (Tbl.create size) in let words = float (Size.words tbl) in let (data, c) = Tbl.fold tbl ~init:(0, 0) ~f:(fun ~key ~data (w, c) -> (w + Size.words key + Size.words data, c + 1)) in (words -. float data) /. float c ;; let compact () = let current_control = Gc.get () in Gc.set {current_control with Gc.Control.space_overhead = 5}; Gc.compact (); Gc.set current_control ;; let trial tests = (* turn off compaction *) Gc.set { (Gc.get ()) with Gc.Control. max_overhead = 1_000_000; }; let samples = Strings.create () in if List.mem tests `insert_and_lookup then begin let (rs, tbl) = insert samples 1 1_000_000 in Printf.printf "insert,"; Stats.print rs; let rs = lookup samples tbl in Printf.printf "lookup,"; Stats.print rs; end; if List.mem tests `insert_and_lookup_no_growth then begin Printf.printf "insert no growth,"; let (rs, tbl) = insert samples 1_000_000 1_000_000 in Stats.print rs; Printf.printf "lookup no growth,"; let rs = lookup samples tbl in Stats.print rs end; if List.mem tests `memory_overhead then begin Printf.printf "memory overhead,"; Printf.printf "%f\n%!" (memory_overhead samples 1 10_000); end; if List.mem tests `memory_overhead_no_growth then begin Printf.printf "memory overhead,"; Printf.printf "%f\n%!" (memory_overhead samples 10_000 10_000); end; if List.mem tests `worst_case then begin Printf.printf "worst case insert,"; let (rs, tbl) = worst_case_insert samples in Stats.print rs; Printf.printf "worst case lookup,"; let rs = worst_case_lookup samples tbl in Stats.print rs end ;; let run tests trials = for i = 1 to trials do trial tests done end module Arg = struct open Arg type tests = [ `insert_and_lookup | `insert_and_lookup_no_growth | `memory_overhead | `memory_overhead_no_growth | `worst_case ] with sexp type t = [ `Htree | `Fastcache | `Standard | `Super_htree | `Standard_map | `Fast_map ] let tbl = ref `Htree let tests = ref "(insert_and_lookup insert_and_lookup_no_growth memory_overhead memory_overhead_no_growth)" let trials = ref 1 let args = Arg.align [ ("-htree", Unit (fun () -> tbl := `Htree), " run tests on the htree"); ("-fastcache", Unit (fun () -> tbl := `Fastcache), " run tests on the fastcache"); ("-standard", Unit (fun () -> tbl := `Standard), " run tests on the standard"); ("-separate-chaining", Unit (fun () -> tbl := `Separate_chaining), " run tests on the separate chaining hashtbl"); ("-core-extended-table", Unit (fun () -> tbl := `Super_htree), " run tests on the super htree aka Core_extended.Table_new"); ("-standard-map", Unit (fun () -> tbl := `Standard_map), " run tests on the standard map (from the caml stdlib)"); ("-fast-map", Unit (fun () -> tbl := `Fast_map), " run tests on the optimized map in core_extended"); ("-tests", Set_string tests, sprintf " list of tests to run %s" !tests); ("-trials", Set_int trials, " number of times to run the specified tests") ] let parse () = Arg.parse args (fun a -> raise (Bad a)) (sprintf "usage %s: \n\nWarning! The worst case test does not work with the standard hashtbl, it will give wrong results" Sys.argv.(0)); (!tbl, List.t_of_sexp tests_of_sexp (Sexp.of_string !tests), !trials) end let () = let (tbl, tests, trials) = Arg.parse () in match tbl with | `Htree -> let module M = Make (Of_table_new (Htree)) in M.run tests trials | `Super_htree -> let module M = Make (Of_table_new (Table_new)) in M.run tests trials | `Fastcache -> let module M = Make (Of_table_new (Hashtbl_fastcache)) in M.run tests trials | `Standard -> let module M = Make (Std_hashtbl) in M.run tests trials | `Separate_chaining -> let module M = Make (Of_table_new (Hashtbl_separate_chaining)) in M.run tests trials | `Standard_map -> let module M = Make (Of_map (Core.Std.Map)) in M.run tests trials | `Fast_map -> () (* | `Fast_map -> * let module M = Make (Of_map (Core_extended.Fast_map)) in * M.run tests trials *) core-113.00.00/test/hashtbl/htree.ml000066400000000000000000000325121256461075500170270ustar00rootroot00000000000000open Core.Std open Core_extended.Std module Avltree = struct type ('k, 'v) t = | Empty | Node of ('k, 'v) node | Leaf of 'k * 'v (* This record adds an indirection, but it is necessary to make insert performance decent, otherwise we are killed by allocation. It IS possible to get rid of it by collapsing it's fields into a constructor. However, in order to set the fields we'd need to use the Obj module, and I wasn't willing to contamplate that just yet. (E.G. Obj.set_field ) *) and ('k, 'v) node = { key: 'k; mutable value: 'v; mutable left: ('k, 'v) t; mutable right: ('k, 'v) t; mutable height: int; } let invariant t compare = let rec binary_tree = function | Empty | Leaf _ -> () | Node {left = left; right = right; key = key} -> begin match left with | Empty -> () | Leaf (left_key, _) | Node {key = left_key} -> assert (compare left_key key < 0) end; begin match right with | Empty -> () | Leaf (right_key, _) | Node {key = right_key} -> assert (compare right_key key > 0) end; assert (compare key key = 0); binary_tree left; binary_tree right in let rec height = function | Empty -> 0 | Leaf _ -> 1 | Node {left = left; right = right} -> Int.max (height left) (height right) + 1 in let rec balanced = function | Empty | Leaf _ -> () | Node {left = left; right = right} -> assert (abs (height left - height right) < 3); balanced left; balanced right in binary_tree t; balanced t let empty = Empty let height = function | Empty -> 0 | Leaf _ -> 1 | Node n -> n.height let update_height n = let new_height = (Int.max (height n.left) (height n.right)) + 1 in n.height <- new_height let balance tree = match tree with | Empty | Leaf _ -> tree | Node ({left = left; right = right} as root_node) as root -> let hl = height left and hr = height right in (* + 2 is critically important, lowering it to 1 will break the Leaf assumptions in the code below, and will force us to promote leaf nodes in the balance routine. It's also faster, since it will balance less often. *) if hl > hr + 2 then begin match left with (* It cannot be a leaf, because even if right is empty, a leaf is only height 1 *) | Empty | Leaf _ -> assert false | Node left_node -> if height left_node.left >= height left_node.right then begin root_node.left <- left_node.right; left_node.right <- root; update_height root_node; update_height left_node; left end else begin (* if right is a leaf, then left must be empty. That means height is 2. Even if hr is empty we still can't get here. *) match left_node.right with | Empty | Leaf _ -> assert false | Node lr_node as lr -> left_node.right <- lr_node.left; root_node.left <- lr_node.right; lr_node.right <- root; lr_node.left <- left; update_height left_node; update_height root_node; update_height lr_node; lr end end else if hr > hl + 2 then begin (* see above for an explanation of why right cannot be a leaf *) match right with | Empty | Leaf _ -> assert false | Node right_node -> if height right_node.right >= height right_node.left then begin root_node.right <- right_node.left; right_node.left <- root; update_height root_node; update_height right_node; right end else begin (* see above for an explanation of why this cannot be a leaf *) match right_node.left with | Empty | Leaf _ -> assert false | Node rl_node as rl -> right_node.left <- rl_node.right; root_node.right <- rl_node.left; rl_node.left <- root; rl_node.right <- right; update_height right_node; update_height root_node; update_height rl_node; rl end end else tree ;; let set_left node tree = let tree = balance tree in if phys_equal node.left tree then () else node.left <- tree; update_height node let set_right node tree = let tree = balance tree in if phys_equal node.right tree then () else node.right <- tree; update_height node let balance_root tree = let tree = balance tree in begin match tree with | Empty | Leaf _ -> () | Node node -> update_height node end; tree let new_node k v = { key = k; value = v; left = Empty; right = Empty; height = 1 } let add = let rec add t added compare k v = match t with | Empty -> added := true; Leaf (k, v) | Leaf (k', _) -> let c = compare k' k in (* This compare is reversed on purpose, we are pretending that the leaf was just inserted instead of the other way round, that way we only allocate one node. *) if c = 0 then begin added := false; Leaf (k, v) end else begin (* going to be the new root node *) let node = new_node k v in added := true; if c < 0 then set_left node t else set_right node t; Node node end | Node node -> let c = compare k node.key in if c = 0 then begin added := false; node.value <- v end else if c < 0 then set_left node (add node.left added compare k v) else set_right node (add node.right added compare k v); t in fun t compare ~added ~key ~data -> balance_root (add t added compare key data) let rec find t compare k = (* A little manual unrolling of the recursion. This is really worth 5% on average *) match t with | Empty -> None | Leaf (k', v) -> if compare k k' = 0 then Some v else None | Node node -> let c = compare k node.key in if c = 0 then Some node.value else if c < 0 then begin match node.left with | Empty -> None | Leaf (k', v) -> if compare k k' = 0 then Some v else None | Node node -> let c = compare k node.key in if c = 0 then Some node.value else find (if c < 0 then node.left else node.right) compare k end else begin match node.right with | Empty -> None | Leaf (k', v) -> if compare k k' = 0 then Some v else None | Node node -> let c = compare k node.key in if c = 0 then Some node.value else find (if c < 0 then node.left else node.right) compare k end ;; let mem t compare k = Option.is_some (find t compare k) let rec min_elt tree = match tree with | Empty -> Empty | Leaf _ -> tree | Node {left = Empty} -> tree | Node node -> min_elt node.left let rec remove_min_elt tree = match tree with | Empty -> assert false | Leaf _ -> Empty (* This must be the root *) | Node ({left = Empty} as node) -> node.right | Node ({left = Leaf _} as node) -> set_left node Empty; tree | Node node -> set_left node (remove_min_elt node.left); tree let merge = let do_merge t1 t2 tree node = set_right node (remove_min_elt t2); set_left node t1; tree in fun t1 t2 -> match (t1, t2) with | (Empty, t) -> t | (t, Empty) -> t | (_, _) -> let tree = min_elt t2 in match tree with | Empty -> Empty | Leaf (k, v) -> let node = new_node k v in do_merge t1 t2 (Node node) node | Node node -> do_merge t1 t2 tree node let remove = let rec remove t removed compare k = match t with | Empty -> removed := false; Empty | Leaf (k', _) -> if compare k k' = 0 then begin removed := true; Empty end else begin removed := false; t end | Node node -> let c = compare k node.key in if c = 0 then begin removed := true; merge node.left node.right end else if c < 0 then begin set_left node (remove node.left removed compare k); t end else begin set_right node (remove node.right removed compare k); t end in fun t ~removed ~compare k -> balance_root (remove t removed compare k) (* estokes: for a real tree implementation we probably want fold_right, that way the elements come in order, but this is a hashtbl, so we don't care. *) let rec fold t ~init ~f = match t with | Empty -> init | Leaf (key, data) -> f ~key ~data init | Node node -> let init = f ~key:node.key ~data:node.value init in fold node.right ~init:(fold node.left ~init ~f) ~f let iter t ~f = fold t ~init:() ~f:(fun ~key ~data () -> f ~key ~data) end module X = Table_new_intf module T : X.Basic = struct type ('k, 'v) t = { mutable table : ('k, 'v) Avltree.t array; mutable array_length: int; mutable length : int; mutable params : X.params; added_or_removed : bool ref; hashable: 'k X.hashable; } let create ?(params = X.default_params) hashable = let size = Int.min (Int.max 1 params.X.initial_size) Sys.max_array_length in { table = Array.create ~len:size Avltree.empty; array_length = size; length = 0; params = params; added_or_removed = ref false; hashable = hashable; } ;; let hashable t = t.hashable let get_params t = t.params let set_params t p = t.params <- p let slot t key = t.hashable.X.hash key mod t.array_length let really_add t ~key ~data = let i = slot t key in let root = t.table.(i) in let new_root = (* The avl tree might replace the entry, in that case the table did not get bigger, so we should not increment length, we pass in the bool ref t.added so that it can tell us whether it added or replaced. We do it this way to avoid extra allocation. Since the bool is an immediate it does not go through the write barrier. *) Avltree.add root t.hashable.X.compare ~added:t.added_or_removed ~key ~data in if t.added_or_removed.contents then t.length <- t.length + 1; if not (phys_equal new_root root) then t.table.(i) <- new_root ;; let maybe_resize_table t = let should_grow = t.params.X.grow && t.length >= t.array_length * t.params.X.load_factor in if should_grow then begin let new_array_length = Int.min (t.array_length * t.params.X.load_factor) Sys.max_array_length in if new_array_length > t.array_length then begin let new_table = Array.init new_array_length ~f:(fun _ -> Avltree.empty) in let old_table = t.table in t.array_length <- new_array_length; t.table <- new_table; t.length <- 0; for i = 0 to Array.length old_table - 1 do Avltree.iter old_table.(i) ~f:(fun ~key ~data -> really_add t ~key ~data) done end end ;; let add t ~key ~data = maybe_resize_table t; really_add t ~key ~data ;; let clear t = for i = 0 to t.array_length - 1 do t.table.(i) <- Avltree.empty; done; t.length <- 0 ;; let find t key = Avltree.find t.table.(slot t key) t.hashable.X.compare key let mem t key = Avltree.mem t.table.(slot t key) t.hashable.X.compare key let remove t key = let i = slot t key in let root = t.table.(i) in let new_root = Avltree.remove root ~removed:t.added_or_removed ~compare:t.hashable.X.compare key in if not (phys_equal root new_root) then t.table.(i) <- new_root; if t.added_or_removed.contents then t.length <- t.length - 1 ;; let length t = t.length let fold = (* this is done recursivly to avoid the write barrier in the case that the accumulator is a structured block, Array.fold does this with a for loop and a ref cell, when it is fixed, we can use it. *) let rec loop buckets i len init f = if i < len then loop buckets (i + 1) len (Avltree.fold buckets.(i) ~init ~f) f else init in fun t ~init ~f -> loop t.table 0 t.array_length init f ;; let invariant t = assert (Array.length t.table = t.array_length); let real_len = fold t ~init:0 ~f:(fun ~key:_ ~data:_ i -> i + 1) in assert (real_len = t.length); for i = 0 to t.array_length - 1 do Avltree.invariant t.table.(i) t.hashable.X.compare done ;; end include Table_new_intf.Make (T) core-113.00.00/test/hashtbl/htree.mli000066400000000000000000000000311256461075500171670ustar00rootroot00000000000000include Table_new_intf.S core-113.00.00/test/hashtbl/table_new.ml000066400000000000000000000353031256461075500176610ustar00rootroot00000000000000(*pp camlp4o -I `ocamlfind query sexplib` -I `ocamlfind query type_conv` -I `ocamlfind query bin_prot` pa_type_conv.cmo pa_sexp_conv.cmo pa_bin_prot.cmo *) open Core.Std module Avltree = struct type ('k, 'v) t = | Empty | Node of ('k, 'v) t * 'k * 'v * int * ('k, 'v) t | Leaf of 'k * 'v (* We do this 'crazy' magic because we want to remove a level of indirection in the tree. If we didn't do this, we'd need to use a record, and then the variant would be a block with a pointer to the record. Where as now the 'record' is tagged with the constructor, thus removing a level of indirection. This is even reasonably safe, certainly no more dangerous than a C binding. The extra checking is probably free, since the block will already be in L1 cache, and the branch predictor is very likely to predict correctly. *) let set_field f n v = Obj.set_field (Obj.repr f) n (Obj.repr v) let update_left (n: ('k, 'v) t) (u: ('k, 'v) t) : unit = match n with | Node _ -> set_field n 0 u | _ -> assert false let update_right (n: ('k, 'v) t) (u: ('k, 'v) t) : unit = match n with | Node _ -> set_field n 4 u | _ -> assert false let update_val (n : ('k, 'v) t) (u: 'v) : unit = match n with | Node _ -> set_field n 2 u | _ -> assert false let update_height (n: ('k, 'v) t) (u: int) : unit = match n with | Node _ -> set_field n 3 u | _ -> assert false let update_leaf_val (n: ('k, 'v) t) (u: 'v) : unit = match n with | Leaf _ -> set_field n 1 u | _ -> assert false let invariant t compare = let rec binary_tree = function | Empty | Leaf _ -> () | Node (left, key, _value, _height, right) -> begin match left with | Empty -> () | Leaf (left_key, _) | Node (_, left_key, _, _, _) -> assert (compare left_key key < 0) end; begin match right with | Empty -> () | Leaf (right_key, _) | Node (_, right_key, _, _, _) -> assert (compare right_key key > 0) end; assert (compare key key = 0); binary_tree left; binary_tree right in let rec height = function | Empty -> 0 | Leaf _ -> 1 | Node (left, _k, _v, _h, right) -> Int.max (height left) (height right) + 1 in let rec balanced = function | Empty | Leaf _ -> () | Node (left, _k, _v, _h, right) -> assert (abs (height left - height right) < 3); balanced left; balanced right in binary_tree t; balanced t let empty = Empty let height = function | Empty -> 0 | Leaf _ -> 1 | Node (_l, _k, _v, height, _r) -> height let update_height n = match n with | Node (left, _, _, _, right) -> let new_height = (Int.max (height left) (height right)) + 1 in update_height n new_height | _ -> assert false let balance tree = match tree with | Empty | Leaf _ -> tree | Node (left, _k, _v, _h, right) as root_node -> let hl = height left and hr = height right in (* + 2 is critically important, lowering it to 1 will break the Leaf assumptions in the code below, and will force us to promote leaf nodes in the balance routine. It's also faster, since it will balance less often. *) if hl > hr + 2 then begin match left with (* It cannot be a leaf, because even if right is empty, a leaf is only height 1 *) | Empty | Leaf _ -> assert false | Node (left_node_left, _, _, _, left_node_right) as left_node -> if height left_node_left >= height left_node_right then begin update_left root_node left_node_right; update_right left_node root_node; update_height root_node; update_height left_node; left_node end else begin (* if right is a leaf, then left must be empty. That means height is 2. Even if hr is empty we still can't get here. *) match left_node_right with | Empty | Leaf _ -> assert false | Node (lr_left, _, _, _, lr_right) as lr_node -> update_right left_node lr_left; update_left root_node lr_right; update_right lr_node root_node; update_left lr_node left_node; update_height left_node; update_height root_node; update_height lr_node; lr_node end end else if hr > hl + 2 then begin (* see above for an explanation of why right cannot be a leaf *) match right with | Empty | Leaf _ -> assert false | Node (right_node_left, _, _, _, right_node_right) as right_node -> if height right_node_right >= height right_node_left then begin update_right root_node right_node_left; update_left right_node root_node; update_height root_node; update_height right_node; right_node end else begin (* see above for an explanation of why this cannot be a leaf *) match right_node_left with | Empty | Leaf _ -> assert false | Node (rl_left, _, _, _, rl_right) as rl_node -> update_left right_node rl_right; update_right root_node rl_left; update_left rl_node root_node; update_right rl_node right; update_height right_node; update_height root_node; update_height rl_node; rl_node end end else tree ;; let set_left node tree = let tree = balance tree in match node with | Node (left, _, _, _, _) -> if phys_equal left tree then () else update_left node tree; update_height node | _ -> assert false let set_right node tree = let tree = balance tree in match node with | Node (_, _, _, _, right) -> if phys_equal right tree then () else update_right node tree; update_height node | _ -> assert false let balance_root tree = let tree = balance tree in begin match tree with | Empty | Leaf _ -> () | Node _ as node -> update_height node end; tree let new_node k v = Node (Empty, k, v, 1, Empty) let add = let rec add t added compare k v = match t with | Empty -> added := true; Leaf (k, v) | Leaf (k', _) -> let c = compare k' k in (* This compare is reversed on purpose, we are pretending that the leaf was just inserted instead of the other way round, that way we only allocate one node. *) if c = 0 then begin added := false; update_leaf_val t v; t end else begin (* going to be the new root node *) let node = new_node k v in added := true; if c < 0 then set_left node t else set_right node t; node end | Node (left, k', _, _, right) -> let c = compare k k' in if c = 0 then begin added := false; update_val t v; end else if c < 0 then set_left t (add left added compare k v) else set_right t (add right added compare k v); t in fun t compare ~added ~key ~data -> balance_root (add t added compare key data) let rec find t compare k = (* A little manual unrolling of the recursion. This is really worth 5% on average *) match t with | Empty -> None | Leaf (k', v) -> if compare k k' = 0 then Some v else None | Node (left, k', v, _, right) -> let c = compare k k' in if c = 0 then Some v else if c < 0 then begin match left with | Empty -> None | Leaf (k', v) -> if compare k k' = 0 then Some v else None | Node (left, k', v, _, right) -> let c = compare k k' in if c = 0 then Some v else find (if c < 0 then left else right) compare k end else begin match right with | Empty -> None | Leaf (k', v) -> if compare k k' = 0 then Some v else None | Node (left, k', v, _, right) -> let c = compare k k' in if c = 0 then Some v else find (if c < 0 then left else right) compare k end ;; let mem t compare k = Option.is_some (find t compare k) let rec min_elt tree = match tree with | Empty -> Empty | Leaf _ -> tree | Node (Empty, _, _, _, _) -> tree | Node (left, _, _, _, _) -> min_elt left let rec remove_min_elt tree = match tree with | Empty -> assert false | Leaf _ -> Empty (* This must be the root *) | Node (Empty, _, _, _, right) -> right | Node (Leaf _, _, _, _, _) as node -> set_left node Empty; tree | Node (left, _, _, _, _) as node -> set_left node (remove_min_elt left); tree let merge = let do_merge t1 t2 node = set_right node (remove_min_elt t2); set_left node t1; node in fun t1 t2 -> match (t1, t2) with | (Empty, t) -> t | (t, Empty) -> t | (_, _) -> let tree = min_elt t2 in match tree with | Empty -> Empty | Leaf (k, v) -> let node = new_node k v in do_merge t1 t2 node | Node _ as node -> do_merge t1 t2 node let remove = let rec remove t removed compare k = match t with | Empty -> removed := false; Empty | Leaf (k', _) -> if compare k k' = 0 then begin removed := true; Empty end else begin removed := false; t end | Node (left, k', _, _, right) -> let c = compare k k' in if c = 0 then begin removed := true; merge left right end else if c < 0 then begin set_left t (remove left removed compare k); t end else begin set_right t (remove right removed compare k); t end in fun t ~removed ~compare k -> balance_root (remove t removed compare k) (* estokes: for a real tree implementation we probably want fold_right, that way the elements come in order, but this is a hashtbl, so we don't care. *) let rec fold t ~init ~f = match t with | Empty -> init | Leaf (key, data) -> f ~key ~data init | Node (left, key, data, _, right) -> let init = f ~key ~data init in fold right ~init:(fold left ~init ~f) ~f let iter t ~f = fold t ~init:() ~f:(fun ~key ~data () -> f ~key ~data) end module X = Table_new_intf module T : X.Basic = struct type ('k, 'v) t = { mutable table : ('k, 'v) Avltree.t array; mutable array_length: int; mutable length : int; mutable params : X.params; added_or_removed : bool ref; hashable: 'k X.hashable; } let create ?(params = X.default_params) hashable = let size = Int.min (Int.max 1 params.X.initial_size) Sys.max_array_length in { table = Array.create ~len:size Avltree.empty; array_length = size; length = 0; params = params; added_or_removed = ref false; hashable = hashable; } ;; let hashable t = t.hashable let get_params t = t.params let set_params t p = t.params <- p let slot t key = t.hashable.X.hash key mod t.array_length let really_add t ~key ~data = let i = slot t key in let root = t.table.(i) in let new_root = (* The avl tree might replace the entry, in that case the table did not get bigger, so we should not increment length, we pass in the bool ref t.added so that it can tell us whether it added or replaced. We do it this way to avoid extra allocation. Since the bool is an immediate it does not go through the write barrier. *) Avltree.add root t.hashable.X.compare ~added:t.added_or_removed ~key ~data in if t.added_or_removed.contents then t.length <- t.length + 1; if not (phys_equal new_root root) then t.table.(i) <- new_root ;; let maybe_resize_table t = let should_grow = t.params.X.grow && t.length >= t.array_length * t.params.X.load_factor in if should_grow then begin let new_array_length = Int.min (t.array_length * t.params.X.load_factor) Sys.max_array_length in if new_array_length > t.array_length then begin let new_table = Array.init new_array_length ~f:(fun _ -> Avltree.empty) in let old_table = t.table in t.array_length <- new_array_length; t.table <- new_table; t.length <- 0; for i = 0 to Array.length old_table - 1 do Avltree.iter old_table.(i) ~f:(fun ~key ~data -> really_add t ~key ~data) done end end ;; let add t ~key ~data = maybe_resize_table t; really_add t ~key ~data ;; let clear t = for i = 0 to t.array_length - 1 do t.table.(i) <- Avltree.empty; done; t.length <- 0 ;; let find t key = Avltree.find t.table.(slot t key) t.hashable.X.compare key let mem t key = Avltree.mem t.table.(slot t key) t.hashable.X.compare key let remove t key = let i = slot t key in let root = t.table.(i) in let new_root = Avltree.remove root ~removed:t.added_or_removed ~compare:t.hashable.X.compare key in if not (phys_equal root new_root) then t.table.(i) <- new_root; if t.added_or_removed.contents then t.length <- t.length - 1 ;; let length t = t.length let fold = (* this is done recursivly to avoid the write barrier in the case that the accumulator is a structured block, Array.fold does this with a for loop and a ref cell, when it is fixed, we can use it. *) let rec loop buckets i len init f = if i < len then loop buckets (i + 1) len (Avltree.fold buckets.(i) ~init ~f) f else init in fun t ~init ~f -> loop t.table 0 t.array_length init f ;; let invariant t = assert (Array.length t.table = t.array_length); let real_len = fold t ~init:0 ~f:(fun ~key:_ ~data:_ i -> i + 1) in assert (real_len = t.length); for i = 0 to t.array_length - 1 do Avltree.invariant t.table.(i) t.hashable.X.compare done ;; end include Table_new_intf.Make (T) core-113.00.00/test/hashtbl/table_new.mli000066400000000000000000000000311256461075500200200ustar00rootroot00000000000000include Table_new_intf.S core-113.00.00/test/hashtbl/table_new_intf.ml000066400000000000000000000213141256461075500206760ustar00rootroot00000000000000 open Core.Std hash: 'k -> int; compare: 'k -> 'k -> int; } external hash_param : int -> int -> 'a -> int = "caml_hash_univ_param" "noalloc" let poly = { hash = (fun z -> hash_param 10 100 z); compare = Pervasives.compare } type params = { load_factor: int; grow: bool; initial_size: int; } with sexp let default_params = { load_factor = 2; grow = true; initial_size = 1; } let size n = { default_params with initial_size = n } module type Basic = sig type ('k, 'v) t val create : ?params:params -> 'k hashable -> ('k, 'v) t val invariant : ('k, 'v) t -> unit val hashable : ('k, 'v) t -> 'k hashable val set_params : (_, _) t -> params -> unit val get_params : (_, _) t -> params val find : ('k, 'v) t -> 'k -> 'v option val fold : ('k, 'v) t -> init:'c -> f:(key:'k -> data:'v -> 'c -> 'c) -> 'c val length : ('k, 'v) t -> int val mem : ('k, 'v) t -> 'k -> bool val clear : ('k, 'v) t -> unit val remove : ('k, 'v) t -> 'k -> unit val add : ('k, 'v) t -> key:'k -> data:'v -> unit end module type S = sig include Basic include Core.Std.Sexpable.S2 with type ('k, 'v) sexpable = ('k, 'v) t module Specialize (Key: sig type t include Core.Std.Sexpable with type t := t val hash : t -> int val compare : t -> t -> int end) : sig val hashable : Key.t hashable module Table : sig type ('k, 'v) z = ('k, 'v) t type 'v t = (Key.t, 'v) z include Core.Std.Sexpable.S1 with type 'v sexpable = 'v t end end val copy : ('k, 'v) t -> ('k, 'v) t val iter : ('k, 'v) t -> f:(key:'k -> data:'v -> unit) -> unit val map : ('k, 'v) t -> f:('v -> 'c) -> ('k, 'c) t val mapi : ('k, 'v) t -> f:(key:'k -> data:'v -> 'c) -> ('k, 'c) t val filter_map : ('k, 'v) t -> f:('v -> 'c option) -> ('k, 'c) t val filter_mapi : ('k, 'v) t -> f:(key:'k -> data:'v -> 'c option) -> ('k, 'c) t val find_default : ('k, 'v) t -> 'k -> default:(unit -> 'v) -> 'v val find_exn : ('k, 'v) t -> 'k -> 'v val iter_vals : ('k, 'v) t -> f:('v -> unit) -> unit val of_alist : ?params:params -> 'k hashable -> ('k * 'v) list -> [ `Ok of ('k, 'v) t | `Duplicate_key of 'k ] val of_alist_exn : 'k hashable -> ('k * 'v) list -> ('k, 'v) t val to_alist : ('k, 'v) t -> ('k * 'v) list val merge : ?params:params -> f:(key:'k -> 'a option -> 'b option -> 'c option) -> ('k, 'a) t -> ('k, 'b) t -> ('k, 'c) t val keys : ('k, 'v) t -> 'k list val data : ('k, 'v) t -> 'v list val filter_inplace : ('k, 'v) t -> f:('v -> bool) -> unit val filteri_inplace : ('k, 'v) t -> f:('k -> 'v -> bool) -> unit val equal : ('k, 'v) t -> ('k, 'v) t -> ('v -> 'v -> bool) -> bool val add_to_groups : ('k, 'v) t -> get_key:('r -> 'k) -> get_data:('r -> 'v) -> combine:('v -> 'v -> 'v) -> rows:'r list -> unit val group : ?params:params -> hashable:'k hashable -> get_key:('r -> 'k) -> get_data:('r -> 'v) -> combine:('v -> 'v -> 'v) -> 'r list -> ('k, 'v) t val create_mapped : ?params:params -> hashable:'k hashable -> get_key:('r -> 'k) -> get_data:('r -> 'v) -> 'r list -> ('k, 'v) t val create_with_key : ?params:params -> hashable:'k hashable -> get_key:('v -> 'k) -> 'v list -> ('k, 'v) t end module Make (Basic : Basic) : S with type ('k, 'v) t = ('k, 'v) Basic.t = struct include Basic let find_exn t id = match find t id with | None -> raise Not_found | Some x -> x let mapi t ~f = let bindings = fold t ~init:[] ~f:(fun ~key ~data bindings -> (key, f ~key ~data) :: bindings) in let new_t = create ~params:(get_params t) (hashable t) in List.iter bindings ~f:(fun (key,data) -> add new_t ~key ~data); new_t let iter t ~f = fold t ~init:() ~f:(fun ~key ~data () -> f ~key ~data) let map t ~f = mapi t ~f:(fun ~key:_ ~data -> f data) let copy t = map t ~f:ident let filter_mapi t ~f = let bindings = fold t ~init:[] ~f:(fun ~key ~data bindings -> match f ~key ~data with | Some new_data -> (key,new_data) :: bindings | None -> bindings) in let new_t = create ~params:(get_params t) (hashable t) in List.iter bindings ~f:(fun (key,data) -> add new_t ~key ~data); new_t let filter_map t ~f = filter_mapi t ~f:(fun ~key:_ ~data -> f data) let remove_all = remove let find_default t id ~default = match find t id with | Some x -> x | None -> let default = default () in add t ~key:id ~data:default; default let iter_vals t ~f = iter t ~f:(fun ~key:_ ~data -> f data) let of_alist ?params hashable lst = let t = create ?params hashable in let res = ref (`Ok t) in List.iter lst ~f:(fun (k, v) -> match mem t k with | true -> res := `Duplicate_key k | false -> add t ~key:k ~data:v); !res let of_alist_exn hashable lst = match of_alist hashable lst with | `Ok v -> v | `Duplicate_key _k -> failwith "Hashtbl.of_alist_exn: duplicate key" let to_alist t = fold ~f:(fun ~key ~data list -> (key, data)::list) ~init:[] t let keys t = fold t ~init:[] ~f:(fun ~key ~data:_ acc -> key :: acc) let data t = fold ~f:(fun ~key:_ ~data list -> data::list) ~init:[] t let add_to_groups groups ~get_key ~get_data ~combine ~rows = List.iter rows ~f:(fun row -> let key = get_key row in let data = get_data row in let data = match find groups key with | None -> data | Some old -> combine old data in add groups ~key ~data) ;; let group ?params ~hashable ~get_key ~get_data ~combine rows = let res = create ?params hashable in add_to_groups res ~get_key ~get_data ~combine ~rows; res ;; let create_mapped ?params ~hashable ~get_key ~get_data rows = let res = create ?params hashable in List.iter rows ~f:(fun r -> let key = get_key r in let data = get_data r in add res ~key ~data); res ;; let create_with_key ?params ~hashable ~get_key rows = create_mapped ?params ~hashable ~get_key ~get_data:(fun x -> x) rows ;; let merge ?params ~f t1 t2 = let t = create ?params (hashable t1) in let unique_keys = create ?params (hashable t1) in let record_key ~key ~data:_ = add unique_keys ~key ~data:() in iter t1 ~f:record_key; iter t2 ~f:record_key; iter unique_keys ~f:(fun ~key ~data:_ -> match f ~key (find t1 key) (find t2 key) with | Some data -> add t ~key ~data | None -> ()); t let filteri_inplace t ~f = let to_remove = fold t ~init:[] ~f:(fun ~key ~data ac -> if f key data then ac else key :: ac) in List.iter to_remove ~f:(fun key -> remove t key); ;; let filter_inplace t ~f = filteri_inplace t ~f:(fun _ data -> f data) ;; let sexp_of_t sexp_of_k sexp_of_d t = let coll ~key:k ~data:v acc = Sexp.List [sexp_of_k k; sexp_of_d v] :: acc in Sexp.List (fold ~f:coll t ~init:[]) let t_of_sexp k_of_sexp d_of_sexp sexp = match sexp with | Sexp.List sexps -> let t = create poly in List.iter sexps ~f:(function | Sexp.List [k_sexp; v_sexp] -> add t ~key:(k_of_sexp k_sexp) ~data:(d_of_sexp v_sexp) | Sexp.List _ | Sexp.Atom _ -> Sexplib.Conv.of_sexp_error "Hashtbl.t_of_sexp: tuple list needed" sexp); t | Sexp.Atom _ -> Sexplib.Conv.of_sexp_error "Hashtbl.t_of_sexp: found atom where list was expected" sexp exception Not_equal let equal t t' equal = try iter t ~f:(fun ~key ~data -> match find t' key with | None -> raise Not_equal | Some data' -> if not (equal data data') then raise Not_equal); true with Not_equal -> false ;; module Specialize (Key: sig type t include Sexpable with type t := t val hash : t -> int val compare : t -> t -> int end) = struct let hashable = { hash = Key.hash; compare = Key.compare } module Table = struct type ('k, 'v) z = ('k, 'v) t type 'v t = (Key.t, 'v) z let sexp_of_t sexp_of_d t = sexp_of_t Key.sexp_of_t sexp_of_d t let t_of_sexp d_of_sexp sexp = match sexp with | Sexp.List sexps -> let t = create hashable in List.iter sexps ~f:(function | Sexp.List [k_sexp; v_sexp] -> add t ~key:(Key.t_of_sexp k_sexp) ~data:(d_of_sexp v_sexp) | Sexp.List _ | Sexp.Atom _ -> Sexplib.Conv.of_sexp_error "Hashtbl.t_of_sexp: tuple list needed" sexp); t | Sexp.Atom _ -> Sexplib.Conv.of_sexp_error "Hashtbl.t_of_sexp: found atom where list was expected" sexp end end end core-113.00.00/test/heap_test.ml000066400000000000000000000077301256461075500162530ustar00rootroot00000000000000open OUnit;; open Core.Std let rec forever f = f (); forever f let to_sorted_list h = List.rev (List.init ~f:(fun _ -> Heap.pop_exn h) (Heap.length h)) let random_heap_and_list gen = let h = Heap.create ~cmp:compare () in let random_list = List.init ~f:(fun _ -> gen ()) 9999 in List.iter ~f:(fun i -> ignore(Heap.add h i)) random_list; (h,random_list) let test = "heap" >::: begin let float_heap () = Heap.of_array [| 0.; 1.; 2.; 3.; |] ~cmp:compare in let int_heap () = Heap.of_array [| 0; 1; 2; 3; |] ~cmp:compare in let empty_heap = Heap.create ~cmp:compare () in let random_heap = Heap.of_array (Array.init 100 ~f:(fun _ -> Random.int 100)) ~cmp:compare in [ "length" >:: (fun () -> "length=4" @? (Heap.length (int_heap ()) = 4); ); "is_empty" >:: (fun () -> "yup" @? Heap.is_empty empty_heap; "nope" @? not (Heap.is_empty (float_heap ())) ); "top" >:: (fun () -> let (h,l) = random_heap_and_list Quickcheck_deprecated.uig in "foo" @? (match Heap.top h with None -> false | Some t -> t = List.hd_exn (List.sort ~cmp:compare l)); "didnaepop" @? (Heap.length h = List.length l) ); "pop" >:: (fun () -> let (h,l) = random_heap_and_list Quickcheck_deprecated.uig in "foo" @? (match Heap.pop h with None -> false | Some t -> t = List.hd_exn (List.sort ~cmp:compare l)); "popped" @? (Heap.length h = List.length l - 1) ); "pop_if" >:: (fun () -> let h = Heap.of_array [| -1; 1; 2; 3; |] ~cmp:compare in "dopop" @? (match Heap.pop_if h (fun i -> i < 0) with None -> false | Some t -> t = -1); "afterdopop" @? (Heap.length h = 3); "dontpop" @? (match Heap.pop_if h (fun i -> i < 0) with None -> true | Some _ -> false); "afterdontpop" @? (Heap.length h = 3); let empty = Heap.create ~cmp:compare () in "empty" @? (match Heap.pop_if empty (fun _ -> true) with None -> true | Some _ -> false) ); "search functions" >:: (fun () -> "yup" @? (Heap.mem (float_heap ()) 0.); "nope" @? not (Heap.mem (float_heap ()) 0.5); "find" @? begin let el = Option.value_exn (Heap.find (int_heap ()) ~f:(fun e -> e = 2)) in 2 = el end ); "iter" >:: (fun () -> "content differs" @? begin let h,l = random_heap_and_list Quickcheck_deprecated.fg in (List.sort ~cmp:Float.compare l) = (to_sorted_list h) end ); "random heap" >:: (fun () -> "rest" @? begin try forever begin fun () -> let top = Heap.pop_exn random_heap in let next = Heap.top_exn random_heap in if top > next then raise Exit end with | _ -> if Heap.is_empty random_heap then true else false end ); "sort" >:: (fun () -> "randomints" @? ( let (h,l) = random_heap_and_list Quickcheck_deprecated.uig in to_sorted_list h = List.sort ~cmp:compare l ); "randomfloats" @? ( let (h,l) = random_heap_and_list Quickcheck_deprecated.fg in to_sorted_list h = List.sort ~cmp:compare l ) ) ] end core-113.00.00/test/int_conversions_test.ml000066400000000000000000000107721256461075500205600ustar00rootroot00000000000000open OUnit;; open Core.Std let () = List.iter [ ("1", "1"); ("12", "12"); ("123", "123"); ("1234", "1_234"); ("12345", "12_345"); ("123456", "123_456"); ("1234567", "1_234_567"); ("+1", "+1"); ("+12", "+12"); ("+123", "+123"); ("+1234", "+1_234"); ("+12345", "+12_345"); ("+123456", "+123_456"); ("+1234567", "+1_234_567"); ("-1", "-1"); ("-12", "-12"); ("-123", "-123"); ("-1234", "-1_234"); ("-12345", "-12_345"); ("-123456", "-123_456"); ("-1234567", "-1_234_567"); ] ~f:(fun (input, expected) -> let got = try Int_conversions.insert_underscores input with exn -> failwithf "input = %s exn = %s" input (Exn.to_string exn) () in if got <> expected then failwithf "input = %s got = %s expected = %s" input got expected ()) ;; module Examples (I : Int_intf.S) = struct open I let two = one + one let examples = [min_value; min_value + one; min_value + two; min_value / two; neg two; neg one; zero; one; two; max_value / two; max_value - two; max_value - one; max_value;] end module Inverses (X : Int_intf.S) (Y : Int_intf.S) (Conv : sig val x_to_y : X.t -> Y.t val y_to_x : Y.t -> X.t option end) = struct open Conv let xs = let module E = Examples (X) in E.examples let ys = let module E = Examples (Y) in E.examples let out_of_range y = assert (y >= x_to_y X.max_value || y <= x_to_y X.min_value) let test = "int_conversions" >:: (fun () -> List.iter xs ~f:(fun x -> let y = x_to_y x in match y_to_x y with | Some x' -> assert (x = x') | None -> out_of_range y); List.iter ys ~f:(fun y -> match y_to_x y with | Some x -> assert (x_to_y x = y) | None -> out_of_range y)) end module Inverses' (X : Int_intf.S) (Y : Int_intf.S) (Conv : sig val x_to_y : X.t -> Y.t option val y_to_x : Y.t -> X.t option end) = struct open Conv let xs = let module E = Examples (X) in E.examples let ys = let module E = Examples (Y) in E.examples let get = function | Some z -> z | None -> failwith "Out_of_range" let y_to_x_exn y = get (y_to_x y) let x_to_y_exn x = get (x_to_y x) let x_out_of_range x = assert (x >= y_to_x_exn Y.max_value || x <= y_to_x_exn Y.min_value) let y_out_of_range y = assert (y >= x_to_y_exn X.max_value || y <= x_to_y_exn X.min_value) let test = "int_conversions" >:: (fun () -> List.iter xs ~f:(fun x -> match x_to_y x with | None -> x_out_of_range x | Some y -> match y_to_x y with | Some x' -> assert (x = x') | None -> y_out_of_range y); List.iter ys ~f:(fun y -> match y_to_x y with | Some x -> assert (x_to_y_exn x = y) | None -> y_out_of_range y)) end module Ii6 = Inverses (Int) (Int64) (struct let x_to_y = Int.to_int64 let y_to_x = Int.of_int64 end) module Ii6' = Inverses (Int) (Int64) (struct let x_to_y = Int64.of_int let y_to_x = Int64.to_int end) module Iin = Inverses (Int) (Nativeint) (struct let x_to_y = Int.to_nativeint let y_to_x = Int.of_nativeint end) module Iin' = Inverses (Int) (Nativeint) (struct let x_to_y = Nativeint.of_int let y_to_x = Nativeint.to_int end) module I36 = Inverses (Int32) (Int64) (struct let x_to_y = Int32.to_int64 let y_to_x = Int32.of_int64 end) module I36' = Inverses (Int32) (Int64) (struct let x_to_y = Int64.of_int32 let y_to_x = Int64.to_int32 end) module I3n = Inverses (Int32) (Nativeint) (struct let x_to_y = Int32.to_nativeint let y_to_x = Int32.of_nativeint end) module I3n' = Inverses (Int32) (Nativeint) (struct let x_to_y = Nativeint.of_int32 let y_to_x = Nativeint.to_int32 end) module In6 = Inverses (Nativeint) (Int64) (struct let x_to_y = Int64.of_nativeint let y_to_x = Int64.to_nativeint end) module In6' = Inverses (Nativeint) (Int64) (struct let x_to_y = Nativeint.to_int64 let y_to_x = Nativeint.of_int64 end) module Ii3 = Inverses' (Int) (Int32) (struct let x_to_y = Int.to_int32 let y_to_x = Int.of_int32 end) module Ii3' = Inverses' (Int) (Int32) (struct let x_to_y = Int32.of_int let y_to_x = Int32.to_int end) let test = TestList [ Ii6.test; Ii6'.test; Iin.test; Iin'.test; I36.test; I36'.test; I3n.test; I3n'.test; In6.test; In6'.test; Ii3.test; Ii3'.test; ] ;; core-113.00.00/test/int_set_test.ml000066400000000000000000000047041256461075500170010ustar00rootroot00000000000000open OUnit open Core.Std module ISet = struct include Set.Make(Int) let of_int_set iset = List.fold (Int_set.ranges iset) ~init:empty ~f:(fun st (lo,hi) -> assert (lo <= hi); let st = ref st in for i = lo to hi do st := add !st i done; !st) end (* add random int between [0..99] 100 times and check the result is correct *) let test_random_0_99 () = let f () = let set = ref ISet.empty in let int_set = ref Int_set.empty in for _i = 0 to 99 do let n = Random.int 100 in set := ISet.add !set n; int_set := Int_set.add !int_set n; done; assert (ISet.equal !set (ISet.of_int_set !int_set)); (* mem *) ISet.iter !set ~f:(fun n -> assert (Int_set.mem !int_set n)); (* ranges returns normalized *) let ranges = Int_set.ranges !int_set in let discrete (x1,x2) (y1,y2) = x2 + 1 < y1 || y2 + 1 < x1 in let rec f = function | [] -> () | x::xs -> List.iter xs ~f:(fun y -> assert (discrete x y)); f xs in f ranges; (* max and min *) assert (Int_set.max !int_set = ISet.max_elt !set); assert (Int_set.min !int_set = ISet.min_elt !set) in for _i = 0 to 999 do f () done; (* max and min for empty *) assert (Int_set.max Int_set.empty = Int_set.min Int_set.empty) (* test for add_range, checking some sensitive cases *) let test_add_range () = let targets = [ [ (0, 100) ], [ (0, 50); (51, 100) ]; [ (0, 100) ], [ (51, 100); (0, 50) ]; [ (0, 100) ], [ (0, 49); (51, 100); (50, 50) ] ] in let iset_of_ranges = List.fold ~init:Int_set.empty ~f:(fun st (x,y) -> Int_set.add_range st x y) in List.iter targets ~f:(fun (answer, subranges) -> let answer = iset_of_ranges answer in let sum = iset_of_ranges subranges in let sum' = iset_of_ranges (List.rev subranges) in assert (answer = sum); assert (answer = sum')) let test_min_and_max () = let set = Int_set.empty in assert_equal None (Int_set.min set); assert_equal None (Int_set.max set); let set = Int_set.add_range set 20 30 in let set = Int_set.add_range set 10 12 in let set = Int_set.add_range set 13 42 in let set = Int_set.add_range set 25 35 in assert_equal (Some 10) (Int_set.min set); assert_equal (Some 42) (Int_set.max set) let test = "int_set" >::: [ "random_0_99" >:: test_random_0_99; "add_range" >:: test_add_range; "test_min_and_max" >:: test_min_and_max; ] core-113.00.00/test/interval_test.ml000066400000000000000000000036201256461075500171540ustar00rootroot00000000000000open OUnit;; open Core.Std let test = "interval" >::: [ "is_empty_or_singleton" >:: (fun () -> let t x = Interval.is_empty_or_singleton x in let i = Interval.create in "singleton1" @? t (i 0 0); "singleton2" @? t (i 10 10); "singleton3" @? t (i "foo" "foo"); "empty1" @? t (i 1 0); "nonempty" @? not (t (i 0 1)); ); "are_disjoint_as_open_intervals" >:: (fun () -> let t x = Interval.are_disjoint_as_open_intervals x in let i = Interval.create in "touching" @? t [i 3 4; i 4 5]; "not touching" @? t [i 3 4; i 5 6]; "overlapping" @? not (t [i 3 5; i 4 6]); ); "contains_set" >:: (fun () -> let module S = Interval.Set in let s1 = S.create [ 1,2; 3,4; 5,6 ] in let s2 = S.create [ 3,5; 10,11 ] in let s3 = S.create [ 3,4 ] in "contains 1" @? (S.contains s2 3); "contains 2" @? (S.contains s2 4); "contains 3" @? (not (S.contains s2 9)); "contains 4" @? (not (S.contains s2 12)); "contains_set 1" @? (not (S.contains_set ~container:s2 ~contained:s1)); "contains_set 2" @? (not (S.contains_set ~container:s1 ~contained:s2)); "contains_set 3" @? (S.contains_set ~container:s1 ~contained:s3); "contains_set 4" @? (S.contains_set ~container:s2 ~contained:s3); ); "half_open_intervals_are_a_partition" >:: (fun () -> "are_a_partition" @? Interval.half_open_intervals_are_a_partition [ Interval.create 0 2; Interval.create 2 4; Interval.create 4 8; ]; "not_a_partition" @? not (Interval.half_open_intervals_are_a_partition [ Interval.create 0 2; Interval.create 2 4; Interval.create 5 8; ]); ); ] core-113.00.00/test/ofday_unit_tests_v1.ml000066400000000000000000032454451256461075500203020ustar00rootroot00000000000000open Core.Std let hand_generated ~create = [ create ~hr:0 ~min:0 ~sec:0 ~ms:0 ~us:0, "00:00:00.000000", "\000\000\000\000\000\000\000\000" ; create ~hr:24 ~min:0 ~sec:0 ~ms:0 ~us:0, "24:00:00.000000", "\000\000\000\000\000\024\245\064" ] let unit_tests ~create = hand_generated ~create (* List.map to avoid a stack overflow *) @ List.map ~f:(fun (hr, min, sec, ms, us, hum, bin) -> create ~hr ~min ~sec ~ms ~us, hum, bin) [ 5, 0, 38, 770, 479, "05:00:38.770479", "\208\038\135\079\177\157\209\064" ; 20, 30, 29, 782, 106, "20:30:29.782106", "\193\148\129\131\092\006\242\064" ; 6, 18, 35, 327, 424, "06:18:35.327424", "\252\202\131\244\212\046\214\064" ; 18, 12, 8, 192, 141, "18:12:08.192141", "\231\225\004\038\006\255\239\064" ; 6, 40, 20, 750, 241, "06:40:20.750241", "\200\211\242\003\048\117\215\064" ; 2, 39, 43, 611, 522, "02:39:43.611522", "\101\087\090\070\206\183\194\064" ; 0, 56, 10, 177, 52, "00:56:10.177052", "\098\075\143\166\090\084\170\064" ; 4, 54, 25, 227, 968, "04:54:25.227968", "\034\024\007\151\078\064\209\064" ; 1, 6, 22, 3, 583, "01:06:22.003583", "\165\135\161\213\001\028\175\064" ; 13, 32, 9, 833, 125, "13:32:09.833125", "\143\194\245\168\058\203\231\064" ; 22, 5, 26, 585, 576, "22:05:26.585576", "\150\240\132\094\105\106\243\064" ; 12, 52, 25, 870, 693, "12:52:25.870693", "\252\144\183\220\059\161\230\064" ; 2, 30, 2, 197, 667, "02:30:02.197667", "\064\250\038\077\025\149\193\064" ; 0, 7, 26, 174, 618, "00:07:26.174618", "\175\116\062\060\203\226\123\064" ; 5, 0, 1, 298, 168, "05:00:01.298168", "\045\060\047\021\083\148\209\064" ; 11, 38, 5, 975, 214, "11:38:05.975214", "\147\253\243\052\191\115\228\064" ; 1, 40, 20, 87, 877, "01:40:20.087877", "\019\105\027\127\022\132\183\064" ; 15, 6, 4, 518, 546, "15:06:04.518546", "\239\199\237\151\144\139\234\064" ; 20, 13, 52, 628, 672, "20:13:52.628672", "\254\094\010\015\010\200\241\064" ; 22, 32, 38, 320, 667, "22:32:38.320667", "\095\184\115\033\101\208\243\064" ; 0, 48, 46, 172, 738, "00:48:46.172738", "\142\121\029\113\088\220\166\064" ; 12, 49, 2, 187, 270, "12:49:02.187270", "\176\167\029\254\197\135\230\064" ; 11, 59, 49, 700, 710, "11:59:49.700710", "\191\096\055\108\182\022\229\064" ; 9, 48, 14, 98, 140, "09:48:14.098140", "\077\127\246\035\195\059\225\064" ; 1, 3, 56, 130, 80, "01:03:56.130080", "\186\131\216\153\066\248\173\064" ; 12, 15, 4, 52, 180, "12:15:04.052180", "\049\100\117\171\001\137\229\064" ; 18, 32, 17, 887, 921, "18:32:17.887921", "\135\166\236\052\030\075\240\064" ; 11, 47, 5, 220, 39, "11:47:05.220039", "\155\058\143\010\039\183\228\064" ; 6, 55, 35, 233, 165, "06:55:35.233165", "\101\228\044\236\206\089\216\064" ; 2, 18, 40, 751, 79, "02:18:40.751079", "\219\078\091\035\096\064\192\064" ; 3, 16, 43, 753, 657, "03:16:43.753657", "\180\035\213\119\224\013\199\064" ; 14, 51, 33, 51, 737, "14:51:33.051737", "\096\090\212\167\161\030\234\064" ; 9, 35, 1, 708, 903, "09:35:01.708903", "\033\088\085\175\182\216\224\064" ; 11, 27, 4, 57, 878, "11:27:04.057878", "\165\246\034\218\001\033\228\064" ; 13, 32, 40, 935, 543, "13:32:40.935543", "\160\223\247\239\029\207\231\064" ; 2, 39, 36, 935, 608, "02:39:36.935608", "\240\192\000\194\119\180\194\064" ; 21, 4, 41, 768, 246, "21:04:41.768246", "\084\081\188\074\156\134\242\064" ; 8, 29, 23, 291, 316, "08:29:23.291316", "\052\221\235\164\210\216\221\064" ; 0, 34, 31, 481, 647, "00:34:31.481647", "\111\130\111\154\246\046\160\064" ; 2, 14, 20, 426, 628, "02:14:20.426628", "\143\027\126\055\109\124\191\064" ; 1, 52, 42, 455, 570, "01:52:42.455570", "\010\075\060\160\116\106\186\064" ; 8, 5, 28, 340, 685, "08:05:28.340685", "\079\117\200\205\021\114\220\064" ; 6, 59, 55, 68, 148, "06:59:55.068148", "\210\109\137\092\196\154\216\064" ; 18, 44, 48, 751, 273, "18:44:48.751273", "\086\214\054\005\012\122\240\064" ; 6, 57, 56, 180, 534, "06:57:56.180534", "\116\122\222\141\011\125\216\064" ; 3, 26, 48, 116, 763, "03:26:48.116763", "\049\009\023\242\014\060\200\064" ; 17, 33, 42, 47, 866, "17:33:42.047866", "\019\071\030\136\193\222\238\064" ; 2, 52, 36, 819, 933, "02:52:36.819933", "\244\133\144\243\104\058\196\064" ; 12, 54, 49, 42, 284, "12:54:49.042284", "\165\249\099\090\033\179\230\064" ; 4, 3, 51, 323, 680, "04:03:51.323680", "\047\163\088\110\169\147\204\064" ; 23, 43, 0, 759, 152, "23:43:00.759152", "\075\145\124\037\076\216\244\064" ; 17, 29, 57, 484, 876, "17:29:57.484876", "\083\172\026\132\175\194\238\064" ; 22, 22, 53, 950, 463, "22:22:53.950463", "\209\176\024\053\223\171\243\064" ; 5, 57, 29, 611, 811, "05:57:29.611811", "\022\083\233\039\103\242\212\064" ; 7, 30, 42, 982, 619, "07:30:42.982619", "\091\205\058\227\190\104\218\064" ; 22, 48, 13, 978, 979, "22:48:13.978979", "\072\226\229\169\223\010\244\064" ; 14, 32, 53, 573, 121, "14:32:53.573121", "\244\217\001\087\178\146\233\064" ; 6, 23, 32, 274, 118, "06:23:32.274118", "\080\057\038\139\017\121\214\064" ; 8, 30, 39, 773, 492, "08:30:39.773492", "\238\150\228\128\241\235\221\064" ; 15, 16, 25, 109, 728, "15:16:25.109728", "\110\075\228\130\035\217\234\064" ; 13, 32, 31, 453, 504, "13:32:31.453504", "\020\210\026\131\238\205\231\064" ; 12, 13, 53, 699, 452, "12:13:53.699452", "\036\041\233\097\054\128\229\064" ; 1, 6, 38, 656, 315, "01:06:38.656315", "\191\009\133\008\080\061\175\064" ; 17, 49, 29, 173, 781, "17:49:29.173781", "\246\043\157\143\037\085\239\064" ; 1, 16, 19, 524, 499, "01:16:19.524499", "\201\003\145\069\134\227\177\064" ; 6, 37, 47, 452, 221, "06:37:47.452221", "\100\089\048\241\220\078\215\064" ; 5, 11, 29, 206, 383, "05:11:29.206383", "\220\010\097\053\077\064\210\064" ; 5, 26, 5, 664, 675, "05:26:05.664675", "\222\002\009\138\106\027\211\064" ; 5, 23, 13, 790, 229, "05:23:13.790229", "\215\167\028\147\114\240\210\064" ; 18, 59, 3, 249, 306, "18:59:03.249306", "\203\073\040\253\115\175\240\064" ; 16, 12, 19, 12, 235, "16:12:19.012235", "\156\167\058\100\096\124\236\064" ; 20, 54, 33, 807, 813, "20:54:33.807813", "\005\083\205\236\156\096\242\064" ; 2, 43, 36, 179, 781, "02:43:36.179781", "\185\085\016\003\023\044\195\064" ; 1, 6, 2, 123, 803, "01:06:02.123803", "\075\088\027\099\063\244\174\064" ; 5, 43, 10, 624, 303, "05:43:10.624303", "\243\145\148\244\167\027\212\064" ; 17, 11, 16, 367, 66, "17:11:16.367066", "\047\050\001\191\139\054\238\064" ; 5, 38, 52, 508, 344, "05:38:52.508344", "\200\069\181\136\032\219\211\064" ; 8, 23, 29, 244, 878, "08:23:29.244878", "\096\198\020\172\079\128\221\064" ; 22, 20, 38, 109, 467, "22:20:38.109467", "\016\120\096\192\097\163\243\064" ; 6, 3, 33, 206, 721, "06:03:33.206721", "\153\183\234\058\077\077\213\064" ; 9, 42, 23, 366, 783, "09:42:23.366783", "\184\179\175\188\235\015\225\064" ; 12, 57, 16, 884, 847, "12:57:16.884847", "\223\167\170\080\156\197\230\064" ; 18, 32, 25, 954, 327, "18:32:25.954327", "\107\099\236\068\159\075\240\064" ; 19, 47, 4, 32, 316, "19:47:04.032316", "\051\200\093\132\128\099\241\064" ; 3, 39, 50, 403, 386, "03:39:50.403386", "\213\006\039\162\051\195\201\064" ; 4, 55, 12, 574, 389, "04:55:12.574389", "\140\020\202\194\036\076\209\064" ; 18, 6, 3, 26, 371, "18:06:03.026371", "\210\254\007\216\096\209\239\064" ; 6, 51, 11, 496, 266, "06:51:11.496266", "\007\120\210\194\223\023\216\064" ; 20, 52, 45, 892, 963, "20:52:45.892963", "\025\146\147\073\222\089\242\064" ; 12, 44, 56, 458, 419, "12:44:56.458419", "\156\082\094\171\014\105\230\064" ; 20, 41, 17, 993, 94, "20:41:17.993094", "\190\136\182\227\223\046\242\064" ; 0, 43, 34, 907, 676, "00:43:34.907676", "\187\158\232\186\208\109\164\064" ; 23, 10, 0, 767, 588, "23:10:00.767588", "\205\090\010\072\140\092\244\064" ; 13, 39, 22, 772, 368, "13:39:22.772368", "\143\024\061\183\088\001\232\064" ; 8, 41, 58, 1, 969, "08:41:58.001969", "\167\149\066\032\128\149\222\064" ; 14, 13, 54, 541, 48, "14:13:54.541048", "\050\229\067\080\081\004\233\064" ; 9, 36, 24, 383, 114, "09:36:24.383114", "\149\074\120\066\012\227\224\064" ; 0, 47, 12, 918, 7, "00:47:12.918007", "\000\117\003\005\214\033\166\064" ; 15, 20, 26, 283, 259, "15:20:26.283259", "\170\045\117\016\073\247\234\064" ; 0, 14, 42, 990, 675, "00:14:42.990675", "\184\175\003\231\236\151\139\064" ; 13, 18, 22, 97, 992, "13:18:22.097992", "\105\030\192\034\195\099\231\064" ; 1, 26, 26, 758, 774, "01:26:26.758774", "\014\075\003\063\194\066\180\064" ; 20, 7, 55, 620, 215, "20:07:55.620215", "\087\144\102\236\185\177\241\064" ; 15, 35, 57, 723, 943, "15:35:57.723943", "\165\130\138\042\183\107\235\064" ; 22, 53, 57, 128, 826, "22:53:57.128826", "\014\218\171\015\082\032\244\064" ; 18, 9, 15, 750, 17, "18:09:15.750017", "\206\166\035\000\120\233\239\064" ; 10, 52, 18, 697, 709, "10:52:18.697709", "\036\211\161\083\086\028\227\064" ; 23, 40, 56, 221, 2, "23:40:56.221002", "\166\100\057\137\131\208\244\064" ; 12, 52, 30, 614, 101, "12:52:30.614101", "\238\035\183\166\211\161\230\064" ; 5, 18, 1, 810, 57, "05:18:01.810057", "\186\080\249\215\115\162\210\064" ; 14, 12, 30, 84, 607, "14:12:30.084607", "\065\189\025\181\194\249\232\064" ; 14, 12, 5, 283, 653, "14:12:05.283653", "\206\116\175\019\169\246\232\064" ; 7, 59, 41, 844, 208, "07:59:41.844208", "\194\253\128\007\118\027\220\064" ; 10, 56, 17, 314, 784, "10:56:17.314784", "\042\229\181\018\042\058\227\064" ; 11, 56, 52, 171, 720, "11:56:52.171720", "\002\241\186\126\133\000\229\064" ; 13, 1, 58, 911, 442, "13:01:58.911442", "\198\105\136\042\221\232\230\064" ; 6, 31, 14, 791, 322, "06:31:14.791322", "\167\007\005\165\178\236\214\064" ; 15, 13, 50, 175, 121, "15:13:50.175121", "\251\090\151\154\197\197\234\064" ; 2, 6, 14, 60, 242, "02:06:14.060242", "\217\011\005\108\015\150\189\064" ; 17, 38, 15, 964, 284, "17:38:15.964284", "\130\030\106\219\254\000\239\064" ; 0, 20, 26, 150, 5, "00:20:26.150005", "\243\036\233\154\153\040\147\064" ; 13, 7, 37, 95, 182, "13:07:37.095182", "\038\031\187\011\035\019\231\064" ; 17, 38, 6, 770, 315, "17:38:06.770315", "\147\164\107\166\216\255\238\064" ; 14, 59, 45, 404, 797, "14:59:45.404797", "\145\214\024\244\044\092\234\064" ; 19, 29, 24, 930, 58, "19:29:24.930058", "\086\127\132\225\078\033\241\064" ; 1, 10, 16, 297, 526, "01:10:16.297526", "\181\247\169\042\076\120\176\064" ; 23, 50, 25, 752, 85, "23:50:25.752085", "\237\071\138\008\028\244\244\064" ; 11, 36, 34, 714, 923, "11:36:34.714923", "\005\051\166\224\086\104\228\064" ; 1, 11, 41, 11, 855, "01:11:41.011855", "\076\229\237\008\003\205\176\064" ; 11, 22, 11, 642, 56, "11:22:11.642056", "\070\006\185\139\116\252\227\064" ; 13, 34, 0, 841, 886, "13:34:00.841886", "\159\232\186\240\026\217\231\064" ; 17, 52, 43, 339, 913, "17:52:43.339913", "\080\058\145\224\106\109\239\064" ; 13, 28, 59, 462, 374, "13:28:59.462374", "\017\143\196\203\110\179\231\064" ; 15, 50, 16, 885, 171, "15:50:16.885171", "\012\034\082\083\028\215\235\064" ; 10, 1, 3, 683, 281, "10:01:03.683281", "\159\029\112\221\245\155\225\064" ; 3, 45, 46, 47, 922, "03:45:46.047922", "\097\223\078\034\006\117\202\064" ; 0, 21, 13, 555, 300, "00:21:13.555300", "\224\045\144\160\056\230\147\064" ; 6, 6, 42, 425, 658, "06:06:42.425658", "\082\013\251\061\155\124\213\064" ; 10, 13, 49, 23, 432, "10:13:49.023432", "\054\119\244\191\160\251\225\064" ; 12, 0, 25, 258, 782, "12:00:25.258782", "\090\048\241\071\040\027\229\064" ; 19, 28, 44, 606, 256, "19:28:44.606256", "\208\125\057\179\201\030\241\064" ; 23, 50, 33, 309, 756, "23:50:33.309756", "\027\181\194\244\148\244\244\064" ; 23, 10, 29, 128, 717, "23:10:29.128717", "\151\142\057\015\082\094\244\064" ; 5, 7, 27, 639, 903, "05:07:27.639903", "\103\182\043\244\232\003\210\064" ; 7, 45, 46, 608, 960, "07:45:46.608960", "\037\093\051\249\166\074\219\064" ; 3, 6, 58, 695, 978, "03:06:58.695978", "\094\158\206\021\089\233\197\064" ; 7, 41, 58, 539, 398, "07:41:58.539398", "\098\048\127\133\162\017\219\064" ; 14, 30, 49, 567, 109, "14:30:49.567109", "\009\198\193\037\050\131\233\064" ; 15, 16, 45, 645, 513, "15:16:45.645513", "\004\225\010\168\180\219\234\064" ; 8, 29, 11, 123, 281, "08:29:11.123281", "\206\253\213\227\199\213\221\064" ; 10, 48, 50, 348, 380, "10:48:50.348380", "\082\208\237\037\075\002\227\064" ; 19, 20, 8, 604, 637, "19:20:08.604637", "\208\216\151\172\137\254\240\064" ; 23, 14, 31, 417, 798, "23:14:31.417798", "\165\244\076\175\118\109\244\064" ; 0, 17, 11, 277, 984, "00:17:11.277984", "\063\115\214\167\028\029\144\064" ; 4, 53, 19, 458, 530, "04:53:19.458530", "\143\054\142\088\221\047\209\064" ; 11, 51, 54, 279, 38, "11:51:54.279038", "\139\025\225\237\072\219\228\064" ; 3, 40, 56, 547, 772, "03:40:56.547772", "\213\148\100\029\070\228\201\064" ; 3, 18, 25, 439, 70, "03:18:25.439070", "\084\029\114\051\184\064\199\064" ; 23, 36, 55, 604, 461, "23:36:55.604461", "\044\076\223\171\121\193\244\064" ; 17, 45, 22, 352, 355, "17:45:22.352355", "\050\254\125\070\075\054\239\064" ; 20, 47, 8, 116, 696, "20:47:08.116696", "\249\159\252\221\193\068\242\064" ; 18, 33, 6, 348, 312, "18:33:06.348312", "\141\154\175\146\037\078\240\064" ; 23, 41, 13, 206, 845, "23:41:13.206845", "\230\179\060\079\147\209\244\064" ; 17, 43, 53, 812, 694, "17:43:53.812694", "\245\216\150\001\058\043\239\064" ; 0, 56, 10, 626, 682, "00:56:10.626682", "\252\141\118\220\064\085\170\064" ; 2, 59, 7, 91, 339, "02:59:07.091339", "\237\016\255\176\139\253\196\064" ; 7, 44, 18, 293, 676, "07:44:18.293676", "\232\107\150\203\146\052\219\064" ; 11, 35, 41, 332, 203, "11:35:41.332203", "\149\047\104\161\170\097\228\064" ; 15, 5, 32, 104, 273, "15:05:32.104273", "\155\084\052\086\131\135\234\064" ; 0, 19, 0, 595, 886, "00:19:00.595886", "\148\136\240\047\098\210\145\064" ; 15, 36, 22, 381, 231, "15:36:22.381231", "\167\090\011\051\204\110\235\064" ; 23, 13, 0, 946, 764, "23:13:00.946764", "\016\002\242\037\207\103\244\064" ; 10, 5, 43, 8, 97, "10:05:43.008097", "\198\163\084\066\224\190\225\064" ; 22, 44, 25, 347, 907, "22:44:25.347907", "\048\238\006\145\149\252\243\064" ; 8, 45, 43, 915, 296, "08:45:43.915296", "\138\172\053\148\250\205\222\064" ; 12, 57, 6, 490, 408, "12:57:06.490408", "\054\030\108\177\079\196\230\064" ; 2, 15, 5, 15, 925, "02:15:05.015925", "\049\042\169\019\004\169\191\064" ; 8, 44, 34, 659, 735, "08:44:34.659735", "\066\038\025\057\170\188\222\064" ; 12, 13, 39, 185, 419, "12:13:39.185419", "\162\211\243\238\101\126\229\064" ; 4, 46, 46, 370, 795, "04:46:46.370795", "\161\243\026\187\151\205\208\064" ; 12, 23, 38, 850, 5, "12:23:38.850005", "\142\175\061\051\091\201\229\064" ; 15, 21, 22, 998, 657, "15:21:22.998657", "\093\134\255\244\095\254\234\064" ; 10, 29, 32, 482, 579, "10:29:32.482579", "\216\131\073\113\143\113\226\064" ; 5, 47, 55, 193, 600, "05:47:55.193600", "\032\065\241\099\204\098\212\064" ; 10, 33, 12, 165, 651, "10:33:12.165651", "\114\083\003\077\005\141\226\064" ; 15, 50, 8, 729, 688, "15:50:08.729688", "\009\166\154\089\023\214\235\064" ; 6, 41, 25, 433, 843, "06:41:25.433843", "\039\110\021\196\091\133\215\064" ; 7, 45, 43, 695, 72, "07:45:43.695072", "\023\069\015\124\236\073\219\064" ; 19, 26, 0, 690, 783, "19:26:00.690783", "\154\121\114\013\139\020\241\064" ; 12, 44, 31, 550, 78, "12:44:31.550078", "\136\045\061\154\241\101\230\064" ; 10, 15, 38, 561, 584, "10:15:38.561584", "\063\002\127\248\081\009\226\064" ; 4, 30, 27, 170, 670, "04:30:27.170670", "\052\186\131\216\149\177\207\064" ; 0, 36, 18, 775, 612, "00:36:18.775612", "\197\028\004\029\141\005\161\064" ; 8, 10, 38, 264, 187, "08:10:38.264187", "\066\151\112\232\144\191\220\064" ; 11, 38, 49, 17, 192, "11:38:49.017192", "\184\060\214\140\032\121\228\064" ; 6, 38, 13, 464, 627, "06:38:13.464627", "\118\226\114\188\093\085\215\064" ; 14, 15, 51, 685, 814, "14:15:51.685814", "\164\051\048\242\245\018\233\064" ; 12, 8, 20, 129, 858, "12:08:20.129858", "\228\246\203\039\132\086\229\064" ; 6, 6, 10, 590, 345, "06:06:10.590345", "\023\101\054\200\165\116\213\064" ; 11, 53, 33, 23, 4, "11:53:33.023004", "\118\226\114\188\160\231\228\064" ; 15, 23, 20, 859, 322, "15:23:20.859322", "\215\217\144\127\027\013\235\064" ; 22, 55, 2, 899, 247, "22:55:02.899247", "\129\210\080\099\110\036\244\064" ; 19, 16, 27, 26, 253, "19:16:27.026253", "\007\068\136\107\176\240\240\064" ; 15, 18, 7, 801, 576, "15:18:07.801576", "\040\182\130\166\249\229\234\064" ; 14, 59, 55, 143, 968, "14:59:55.143968", "\117\199\098\155\100\093\234\064" ; 16, 48, 52, 307, 340, "16:48:52.307340", "\024\178\186\213\137\142\237\064" ; 7, 45, 8, 664, 982, "07:45:08.664982", "\156\169\016\143\042\065\219\064" ; 16, 14, 35, 640, 920, "16:14:35.640920", "\235\168\106\130\116\141\236\064" ; 13, 45, 0, 214, 451, "13:45:00.214451", "\243\087\200\220\134\043\232\064" ; 15, 46, 7, 236, 287, "15:46:07.236287", "\047\193\169\143\231\183\235\064" ; 8, 24, 40, 713, 331, "08:24:40.713331", "\014\017\055\167\045\146\221\064" ; 2, 6, 9, 55, 137, "02:06:09.055137", "\205\091\117\029\014\145\189\064" ; 16, 5, 4, 254, 916, "16:05:04.254916", "\103\153\069\040\008\070\236\064" ; 20, 0, 46, 747, 535, "20:00:46.747535", "\154\066\231\245\235\150\241\064" ; 13, 55, 46, 25, 674, "13:55:46.025674", "\204\071\082\210\064\124\232\064" ; 3, 52, 14, 954, 975, "03:52:14.954975", "\192\236\158\060\122\055\203\064" ; 2, 31, 44, 354, 519, "02:31:44.354519", "\103\235\224\096\045\200\193\064" ; 19, 27, 4, 535, 573, "19:27:04.535573", "\122\254\180\145\136\024\241\064" ; 19, 1, 41, 576, 26, "19:01:41.576026", "\250\009\103\055\089\185\240\064" ; 14, 5, 6, 594, 330, "14:05:06.594330", "\033\089\192\004\083\194\232\064" ; 15, 28, 17, 209, 355, "15:28:17.209355", "\200\065\009\179\038\050\235\064" ; 5, 7, 1, 3, 697, "05:07:01.003697", "\134\087\146\060\064\253\209\064" ; 12, 26, 46, 673, 671, "12:26:46.673671", "\041\124\182\142\213\224\229\064" ; 14, 51, 27, 289, 960, "14:51:27.289960", "\164\049\090\071\233\029\234\064" ; 8, 5, 26, 31, 23, "08:05:26.031023", "\155\228\071\252\129\113\220\064" ; 7, 1, 44, 165, 679, "07:01:44.165679", "\169\023\124\154\010\182\216\064" ; 17, 37, 27, 52, 600, "17:37:27.052600", "\249\049\230\174\225\250\238\064" ; 18, 13, 48, 257, 879, "18:13:48.257879", "\245\186\069\032\196\005\240\064" ; 9, 4, 25, 814, 345, "09:04:25.814345", "\170\125\058\030\116\230\223\064" ; 12, 33, 28, 349, 270, "12:33:28.349270", "\111\071\056\045\011\019\230\064" ; 22, 4, 19, 724, 897, "22:04:19.724897", "\192\152\045\153\059\102\243\064" ; 1, 49, 22, 636, 656, "01:49:22.636656", "\206\058\227\251\162\162\185\064" ; 11, 8, 3, 287, 534, "11:08:03.287534", "\207\128\122\051\105\146\227\064" ; 13, 1, 5, 849, 76, "13:01:05.849076", "\122\110\161\043\059\226\230\064" ; 6, 24, 39, 767, 642, "06:24:39.767642", "\066\233\011\033\241\137\214\064" ; 9, 20, 45, 237, 678, "09:20:45.237678", "\159\228\014\155\167\109\224\064" ; 21, 38, 9, 673, 44, "21:38:09.673044", "\012\201\201\196\026\004\243\064" ; 9, 27, 17, 671, 958, "09:27:17.671958", "\073\016\174\128\181\158\224\064" ; 8, 18, 49, 969, 86, "08:18:49.969086", "\065\073\129\005\126\058\221\064" ; 4, 38, 27, 431, 470, "04:38:27.431470", "\205\088\052\157\219\080\208\064" ; 3, 37, 56, 417, 5, "03:37:56.417005", "\162\122\107\096\053\138\201\064" ; 23, 5, 50, 859, 315, "23:05:50.859315", "\223\021\193\191\237\076\244\064" ; 12, 37, 41, 655, 826, "12:37:41.655826", "\188\206\134\252\180\050\230\064" ; 18, 37, 13, 612, 275, "18:37:13.612275", "\210\222\224\203\153\093\240\064" ; 1, 8, 27, 880, 888, "01:08:27.880888", "\112\063\224\129\225\011\176\064" ; 11, 6, 19, 493, 638, "11:06:19.493638", "\066\235\225\203\111\133\227\064" ; 20, 54, 11, 413, 362, "20:54:11.413362", "\247\120\033\157\054\095\242\064" ; 14, 21, 21, 279, 583, "14:21:21.279583", "\049\012\088\242\040\060\233\064" ; 3, 47, 13, 117, 696, "03:47:13.117696", "\111\155\169\016\143\160\202\064" ; 16, 16, 14, 732, 213, "16:16:14.732213", "\023\245\073\110\215\153\236\064" ; 3, 53, 42, 139, 452, "03:53:42.139452", "\174\041\144\217\017\099\203\064" ; 8, 8, 6, 881, 696, "08:08:06.881696", "\065\015\181\109\184\153\220\064" ; 6, 44, 1, 656, 50, "06:44:01.656050", "\162\035\185\252\105\172\215\064" ; 3, 51, 50, 748, 871, "03:51:50.748871", "\246\066\001\219\095\043\203\064" ; 22, 10, 9, 150, 361, "22:10:09.150361", "\153\239\224\103\018\124\243\064" ; 4, 34, 32, 90, 69, "04:34:32.090069", "\089\196\176\195\005\022\208\064" ; 13, 31, 31, 9, 461, "13:31:31.009461", "\179\039\129\077\096\198\231\064" ; 8, 9, 4, 404, 362, "08:09:04.404362", "\111\039\017\225\025\168\220\064" ; 7, 19, 16, 649, 147, "07:19:16.649147", "\211\219\159\139\041\189\217\064" ; 21, 23, 8, 426, 871, "21:23:08.426871", "\138\175\118\212\198\203\242\064" ; 19, 33, 14, 22, 918, "19:33:14.022918", "\200\067\223\093\160\047\241\064" ; 1, 23, 20, 266, 219, "01:23:20.266219", "\146\170\237\038\068\136\179\064" ; 22, 42, 43, 984, 285, "22:42:43.984285", "\207\160\161\191\063\246\243\064" ; 0, 18, 52, 672, 93, "00:18:52.672093", "\124\187\037\057\176\178\145\064" ; 8, 11, 58, 442, 318, "08:11:58.442318", "\027\040\240\078\156\211\220\064" ; 8, 2, 52, 446, 220, "08:02:52.446220", "\181\084\222\142\028\075\220\064" ; 3, 49, 31, 33, 30, "03:49:31.033030", "\228\184\083\058\132\229\202\064" ; 4, 54, 4, 718, 468, "04:54:04.718468", "\206\052\097\251\045\059\209\064" ; 12, 0, 31, 823, 707, "12:00:31.823707", "\079\200\206\091\250\027\229\064" ; 11, 3, 53, 488, 857, "11:03:53.488857", "\109\111\183\164\047\115\227\064" ; 16, 19, 24, 135, 984, "16:19:24.135984", "\025\030\251\089\132\177\236\064" ; 21, 30, 8, 789, 495, "21:30:08.789495", "\086\130\197\161\012\230\242\064" ; 22, 29, 23, 62, 945, "22:29:23.062945", "\200\157\210\001\049\196\243\064" ; 2, 9, 36, 293, 32, "02:09:36.293032", "\174\040\037\004\075\096\190\064" ; 0, 45, 1, 406, 576, "00:45:01.406576", "\173\190\186\042\208\026\165\064" ; 0, 28, 30, 890, 31, "00:28:30.890031", "\181\085\073\100\143\187\154\064" ; 23, 41, 41, 802, 862, "23:41:41.802862", "\019\211\133\216\092\211\244\064" ; 19, 13, 14, 661, 502, "19:13:14.661502", "\003\031\131\149\170\228\240\064" ; 19, 34, 53, 779, 436, "19:34:53.779436", "\021\226\145\120\220\053\241\064" ; 10, 3, 49, 554, 661, "10:03:49.554661", "\235\108\200\191\177\176\225\064" ; 21, 26, 8, 638, 16, "21:26:08.638016", "\230\067\080\053\010\215\242\064" ; 2, 50, 56, 428, 954, "02:50:56.428954", "\190\244\246\231\054\008\196\064" ; 21, 10, 54, 290, 961, "21:10:54.290961", "\182\184\198\167\228\157\242\064" ; 19, 33, 30, 559, 803, "19:33:30.559803", "\147\253\243\244\168\048\241\064" ; 5, 53, 33, 443, 346, "05:53:33.443346", "\180\230\199\095\092\183\212\064" ; 1, 49, 35, 6, 394, "01:49:35.006394", "\228\132\009\163\001\175\185\064" ; 15, 23, 44, 908, 124, "15:23:44.908124", "\023\016\090\015\029\016\235\064" ; 12, 7, 15, 580, 238, "12:07:15.580238", "\061\072\079\145\114\078\229\064" ; 17, 2, 32, 300, 92, "17:02:32.300092", "\186\137\090\154\009\245\237\064" ; 7, 20, 9, 156, 270, "07:20:09.156270", "\214\226\083\000\074\202\217\064" ; 11, 43, 27, 113, 566, "11:43:27.113566", "\254\041\085\162\227\155\228\064" ; 4, 38, 0, 604, 430, "04:38:00.604430", "\174\042\251\174\038\074\208\064" ; 4, 41, 0, 109, 951, "04:41:00.109951", "\075\235\111\009\007\119\208\064" ; 6, 6, 27, 477, 589, "06:06:27.477589", "\251\115\209\144\222\120\213\064" ; 3, 23, 7, 233, 934, "03:23:07.233934", "\182\159\140\241\157\205\199\064" ; 11, 34, 32, 228, 204, "11:34:32.228204", "\155\121\114\077\007\089\228\064" ; 5, 10, 24, 980, 274, "05:10:24.980274", "\200\040\207\188\062\048\210\064" ; 3, 54, 48, 607, 848, "03:54:48.607848", "\120\152\246\205\077\132\203\064" ; 15, 9, 7, 993, 968, "15:09:07.993968", "\169\250\149\206\127\162\234\064" ; 0, 5, 23, 499, 527, "00:05:23.499527", "\129\007\006\016\254\055\116\064" ; 3, 40, 57, 29, 359, "03:40:57.029359", "\108\036\009\194\131\228\201\064" ; 1, 52, 49, 301, 441, "01:52:49.301441", "\173\196\060\043\077\113\186\064" ; 10, 25, 51, 76, 870, "10:25:51.076870", "\002\019\184\117\226\085\226\064" ; 18, 38, 0, 139, 75, "18:38:00.139075", "\011\181\166\057\130\096\240\064" ; 0, 11, 14, 254, 868, "00:11:14.254868", "\096\230\059\248\009\018\133\064" ; 15, 17, 52, 413, 721, "15:17:52.413721", "\149\210\051\061\013\228\234\064" ; 2, 19, 27, 271, 914, "02:19:27.271914", "\170\244\019\206\162\087\192\064" ; 21, 0, 18, 784, 137, "21:00:18.784137", "\041\061\211\139\044\118\242\064" ; 20, 52, 25, 887, 839, "20:52:25.887839", "\210\170\150\052\158\088\242\064" ; 20, 22, 43, 808, 728, "20:22:43.808728", "\118\197\140\240\060\233\241\064" ; 19, 43, 52, 255, 86, "19:43:52.255086", "\187\014\213\020\132\087\241\064" ; 6, 46, 38, 323, 40, "06:46:38.323040", "\211\246\175\172\148\211\215\064" ; 23, 1, 34, 401, 660, "23:01:34.401660", "\066\009\051\109\230\060\244\064" ; 14, 21, 4, 423, 506, "14:21:04.423506", "\117\116\092\141\013\058\233\064" ; 5, 13, 55, 521, 290, "05:13:55.521290", "\111\187\208\092\225\100\210\064" ; 23, 38, 6, 563, 795, "23:38:06.563795", "\234\231\077\005\233\197\244\064" ; 19, 2, 11, 404, 353, "19:02:11.404353", "\240\217\058\120\054\187\240\064" ; 21, 49, 37, 179, 407, "21:49:37.179407", "\219\223\217\222\018\047\243\064" ; 2, 26, 35, 445, 592, "02:26:35.445592", "\174\157\040\009\185\045\193\064" ; 16, 23, 30, 830, 747, "16:23:30.830747", "\136\187\122\149\090\208\236\064" ; 5, 14, 1, 501, 594, "05:14:01.501594", "\120\184\029\026\096\102\210\064" ; 6, 57, 51, 911, 894, "06:57:51.911894", "\219\166\120\092\250\123\216\064" ; 15, 4, 48, 348, 589, "15:04:48.348589", "\088\030\164\039\011\130\234\064" ; 21, 59, 52, 279, 981, "21:59:52.279981", "\104\091\205\122\132\085\243\064" ; 7, 39, 4, 586, 624, "07:39:04.586624", "\195\099\063\139\037\230\218\064" ; 7, 49, 31, 876, 654, "07:49:31.876654", "\250\096\025\027\248\130\219\064" ; 16, 32, 54, 606, 85, "16:32:54.606085", "\179\094\012\101\211\022\237\064" ; 6, 20, 55, 467, 499, "06:20:55.467499", "\251\236\128\235\221\081\214\064" ; 13, 11, 34, 336, 451, "13:11:34.336451", "\055\227\052\196\202\048\231\064" ; 17, 30, 19, 988, 749, "17:30:19.988749", "\094\241\212\163\127\197\238\064" ; 9, 12, 52, 6, 550, "09:12:52.006550", "\121\088\168\053\128\050\224\064" ; 9, 47, 26, 486, 109, "09:47:26.486109", "\041\118\052\142\207\053\225\064" ; 14, 17, 0, 799, 927, "14:17:00.799927", "\006\130\000\153\153\027\233\064" ; 6, 14, 42, 805, 662, "06:14:42.805662", "\104\089\247\143\179\244\213\064" ; 5, 21, 27, 139, 876, "05:21:27.139876", "\095\119\186\243\200\213\210\064" ; 18, 26, 11, 415, 491, "18:26:11.415491", "\012\228\217\165\054\052\240\064" ; 20, 32, 34, 520, 1, "20:32:34.520001", "\142\145\236\081\040\014\242\064" ; 5, 25, 14, 166, 413, "05:25:14.166413", "\041\182\130\166\138\014\211\064" ; 13, 26, 33, 971, 569, "13:26:33.971569", "\026\223\023\023\063\161\231\064" ; 6, 53, 30, 577, 661, "06:53:30.577661", "\203\215\101\248\164\058\216\064" ; 12, 59, 7, 439, 249, "12:59:07.439249", "\057\235\083\014\110\211\230\064" ; 23, 21, 23, 679, 596, "23:21:23.679596", "\040\014\160\223\058\135\244\064" ; 15, 57, 34, 890, 407, "15:57:34.890407", "\036\210\054\126\220\013\236\064" ; 22, 17, 40, 816, 755, "22:17:40.816755", "\222\176\109\017\077\152\243\064" ; 20, 53, 41, 88, 380, "20:53:41.088380", "\154\037\001\106\081\093\242\064" ; 7, 58, 52, 737, 314, "07:58:52.737314", "\057\015\039\048\047\015\220\064" ; 17, 34, 54, 319, 152, "17:34:54.319152", "\079\065\126\054\202\231\238\064" ; 4, 38, 16, 638, 97, "04:38:16.638097", "\171\204\148\214\040\078\208\064" ; 12, 38, 58, 173, 115, "12:38:58.173115", "\239\119\040\138\069\060\230\064" ; 2, 45, 15, 900, 138, "02:45:15.900138", "\241\211\184\055\243\093\195\064" ; 3, 4, 31, 526, 765, "03:04:31.526765", "\215\023\009\109\195\159\197\064" ; 20, 37, 52, 816, 522, "20:37:52.816522", "\104\095\121\016\013\034\242\064" ; 10, 24, 27, 445, 692, "10:24:27.445692", "\131\222\027\067\110\075\226\064" ; 5, 26, 27, 295, 729, "05:26:27.295729", "\222\083\057\237\210\032\211\064" ; 17, 48, 6, 622, 665, "17:48:06.622665", "\108\038\223\236\211\074\239\064" ; 7, 18, 8, 896, 780, "07:18:08.896780", "\237\240\215\100\057\172\217\064" ; 6, 41, 31, 668, 43, "06:41:31.668043", "\085\109\055\193\234\134\215\064" ; 21, 51, 9, 530, 75, "21:51:09.530075", "\087\236\047\123\216\052\243\064" ; 4, 10, 13, 743, 659, "04:10:13.743659", "\048\214\055\048\223\082\205\064" ; 20, 58, 21, 935, 845, "20:58:21.935845", "\082\155\056\249\222\110\242\064" ; 20, 50, 52, 293, 515, "20:50:52.293515", "\223\200\060\178\196\082\242\064" ; 4, 38, 13, 7, 419, "04:38:13.007419", "\152\138\141\121\064\077\208\064" ; 21, 24, 41, 988, 967, "21:24:41.988967", "\157\015\207\210\159\209\242\064" ; 2, 9, 38, 704, 502, "02:09:38.704502", "\247\057\062\090\180\098\190\064" ; 21, 22, 6, 847, 453, "21:22:06.847453", "\126\224\042\143\237\199\242\064" ; 18, 33, 12, 280, 988, "18:33:12.280988", "\233\069\237\126\132\078\240\064" ; 17, 4, 47, 620, 72, "17:04:47.620072", "\038\060\161\215\243\005\238\064" ; 19, 55, 9, 324, 906, "19:55:09.324906", "\068\162\208\050\213\129\241\064" ; 19, 41, 24, 121, 205, "19:41:24.121205", "\114\167\116\240\065\078\241\064" ; 15, 1, 1, 875, 660, "15:01:01.875660", "\205\030\104\005\188\101\234\064" ; 8, 24, 46, 409, 827, "08:24:46.409827", "\129\006\155\058\154\147\221\064" ; 10, 0, 31, 963, 297, "10:00:31.963297", "\235\058\084\211\254\151\225\064" ; 20, 59, 43, 463, 21, "20:59:43.463021", "\070\181\136\104\247\115\242\064" ; 22, 28, 14, 107, 437, "22:28:14.107437", "\022\220\015\184\225\191\243\064" ; 21, 33, 55, 210, 696, "21:33:55.210696", "\215\196\002\095\051\244\242\064" ; 5, 55, 34, 903, 944, "05:55:34.903944", "\090\239\055\218\185\213\212\064" ; 18, 56, 35, 224, 858, "18:56:35.224858", "\196\179\004\153\051\166\240\064" ; 22, 40, 36, 404, 510, "22:40:36.404510", "\078\122\223\120\070\238\243\064" ; 10, 43, 20, 460, 693, "10:43:20.460693", "\016\063\255\189\014\217\226\064" ; 11, 50, 23, 685, 564, "11:50:23.685564", "\234\233\035\240\245\207\228\064" ; 18, 2, 29, 283, 384, "18:02:29.283384", "\135\082\123\017\169\182\239\064" ; 15, 37, 25, 908, 644, "15:37:25.908644", "\247\148\156\019\189\118\235\064" ; 6, 14, 33, 230, 329, "06:14:33.230329", "\148\216\181\189\078\242\213\064" ; 10, 40, 59, 716, 709, "10:40:59.716709", "\120\182\071\239\118\199\226\064" ; 0, 45, 29, 661, 68, "00:45:29.661068", "\221\064\129\119\082\083\165\064" ; 11, 29, 44, 162, 485, "11:29:44.162485", "\034\190\019\051\005\053\228\064" ; 2, 58, 23, 884, 698, "02:58:23.884698", "\107\184\200\061\241\231\196\064" ; 18, 34, 35, 144, 578, "18:34:35.144578", "\092\005\049\080\178\083\240\064" ; 11, 45, 57, 724, 306, "11:45:57.724306", "\202\198\131\045\183\174\228\064" ; 16, 31, 14, 805, 497, "16:31:14.805497", "\001\165\161\198\089\010\237\064" ; 13, 55, 58, 468, 642, "13:55:58.468642", "\241\129\029\255\206\125\232\064" ; 22, 47, 41, 331, 846, "22:47:41.331846", "\085\192\061\079\213\008\244\064" ; 22, 37, 35, 389, 280, "22:37:35.389280", "\079\170\125\058\246\226\243\064" ; 15, 54, 30, 393, 958, "15:54:30.393958", "\191\206\077\155\204\246\235\064" ; 5, 23, 31, 134, 76, "05:23:31.134076", "\203\128\179\148\200\244\210\064" ; 7, 43, 38, 979, 410, "07:43:38.979410", "\216\071\167\174\190\042\219\064" ; 8, 56, 19, 192, 701, "08:56:19.192701", "\058\147\054\085\204\108\223\064" ; 17, 3, 18, 642, 479, "17:03:18.642479", "\172\030\048\143\212\250\237\064" ; 12, 12, 10, 505, 283, "12:12:10.505283", "\007\065\071\043\080\115\229\064" ; 10, 32, 3, 38, 44, "10:32:03.038044", "\250\012\168\055\097\132\226\064" ; 14, 53, 2, 367, 366, "14:53:02.367366", "\117\087\118\193\203\041\234\064" ; 8, 41, 34, 242, 657, "08:41:34.242657", "\201\057\177\135\143\143\222\064" ; 16, 49, 11, 118, 346, "16:49:11.118346", "\244\140\125\201\227\144\237\064" ; 17, 53, 52, 111, 242, "17:53:52.111242", "\254\097\075\143\003\118\239\064" ; 18, 35, 55, 863, 157, "18:35:55.863157", "\229\182\125\207\189\088\240\064" ; 6, 43, 25, 274, 434, "06:43:25.274434", "\187\159\083\144\081\163\215\064" ; 7, 58, 52, 659, 267, "07:58:52.659267", "\021\055\110\049\042\015\220\064" ; 19, 44, 14, 617, 219, "19:44:14.617219", "\183\007\033\224\233\088\241\064" ; 12, 9, 4, 369, 551, "12:09:04.369551", "\102\158\092\211\011\092\229\064" ; 4, 30, 8, 550, 94, "04:30:08.550094", "\221\237\122\105\070\168\207\064" ; 9, 41, 38, 249, 986, "09:41:38.249986", "\207\163\226\255\071\010\225\064" ; 7, 14, 23, 249, 660, "07:14:23.249660", "\200\239\109\250\207\115\217\064" ; 23, 28, 26, 632, 962, "23:28:26.632962", "\026\195\156\032\170\161\244\064" ; 12, 18, 47, 180, 503, "12:18:47.180503", "\059\058\174\198\229\164\229\064" ; 18, 29, 13, 973, 229, "18:29:13.973229", "\104\146\088\146\159\063\240\064" ; 3, 14, 17, 994, 269, "03:14:17.994269", "\055\227\052\068\255\196\198\064" ; 20, 54, 17, 406, 905, "20:54:17.406905", "\057\209\174\130\150\095\242\064" ; 13, 55, 3, 214, 101, "13:55:03.214101", "\033\087\234\217\230\118\232\064" ; 13, 13, 39, 461, 245, "13:13:39.461245", "\207\223\132\194\110\064\231\064" ; 10, 13, 41, 785, 419, "10:13:41.785419", "\214\006\039\034\185\250\225\064" ; 3, 23, 45, 592, 41, "03:23:45.592041", "\114\222\255\199\203\224\199\064" ; 14, 54, 51, 610, 770, "14:54:51.610770", "\236\134\109\139\115\055\234\064" ; 0, 18, 38, 920, 766, "00:18:38.920766", "\020\069\072\221\174\123\145\064" ; 12, 13, 43, 246, 605, "12:13:43.246605", "\065\043\048\228\231\126\229\064" ; 20, 57, 54, 173, 937, "20:57:54.173937", "\233\041\114\200\034\109\242\064" ; 16, 27, 36, 871, 848, "16:27:36.871848", "\227\198\045\230\027\239\236\064" ; 20, 25, 27, 711, 18, "20:25:27.711018", "\014\105\084\096\123\243\241\064" ; 22, 41, 36, 247, 25, "22:41:36.247025", "\133\124\208\243\003\242\243\064" ; 19, 15, 41, 567, 176, "19:15:41.567176", "\049\036\039\019\217\237\240\064" ; 5, 9, 33, 561, 154, "05:09:33.561154", "\130\119\242\233\099\035\210\064" ; 13, 33, 3, 565, 26, "13:33:03.565026", "\237\103\177\020\242\209\231\064" ; 0, 48, 16, 883, 570, "00:48:16.883570", "\116\123\073\099\196\161\166\064" ; 4, 54, 57, 287, 365, "04:54:57.287365", "\065\043\048\100\082\072\209\064" ; 11, 5, 11, 651, 864, "11:05:11.651864", "\046\228\017\220\244\124\227\064" ; 21, 11, 23, 922, 735, "21:11:23.922735", "\126\198\133\195\190\159\242\064" ; 8, 2, 11, 935, 266, "08:02:11.935266", "\196\236\101\219\251\064\220\064" ; 20, 10, 37, 800, 121, "20:10:37.800121", "\126\173\075\205\220\187\241\064" ; 5, 42, 30, 535, 17, "05:42:30.535017", "\115\241\183\061\162\017\212\064" ; 22, 36, 38, 292, 944, "22:36:38.292944", "\057\012\230\175\100\223\243\064" ; 6, 25, 11, 272, 91, "06:25:11.272091", "\163\094\240\105\209\145\214\064" ; 8, 56, 52, 371, 998, "08:56:52.371998", "\011\179\208\206\023\117\223\064" ; 2, 24, 55, 100, 584, "02:24:55.100584", "\064\191\239\223\140\251\192\064" ; 0, 30, 20, 781, 30, "00:30:20.781030", "\199\012\084\198\031\115\156\064" ; 5, 20, 51, 391, 209, "05:20:51.391209", "\058\121\145\009\217\204\210\064" ; 14, 48, 31, 115, 345, "14:48:31.115345", "\088\255\231\176\227\007\234\064" ; 14, 24, 54, 572, 254, "14:24:54.572254", "\224\158\231\079\210\086\233\064" ; 9, 59, 56, 842, 884, "09:59:56.842884", "\202\221\231\248\154\147\225\064" ; 12, 43, 27, 675, 933, "12:43:27.675933", "\042\062\062\161\245\093\230\064" ; 1, 21, 7, 241, 369, "01:21:07.241369", "\069\217\091\202\061\003\179\064" ; 20, 25, 34, 5, 687, "20:25:34.005687", "\113\064\075\023\224\243\241\064" ; 18, 12, 57, 150, 97, "18:12:57.150097", "\163\028\204\102\146\002\240\064" ; 18, 5, 32, 964, 883, "18:05:32.964883", "\047\080\082\224\158\205\239\064" ; 12, 50, 10, 330, 432, "12:50:10.330432", "\050\033\230\146\074\144\230\064" ; 18, 40, 21, 626, 823, "18:40:21.626823", "\214\141\119\007\090\105\240\064" ; 19, 9, 14, 62, 879, "19:09:14.062879", "\010\105\141\001\161\213\240\064" ; 4, 38, 48, 644, 632, "04:38:48.644632", "\125\147\166\065\041\086\208\064" ; 20, 52, 38, 113, 259, "20:52:38.113259", "\079\171\232\207\097\089\242\064" ; 9, 12, 32, 146, 140, "09:12:32.146140", "\020\203\045\173\004\048\224\064" ; 12, 32, 34, 390, 136, "12:32:34.390136", "\032\126\254\123\076\012\230\064" ; 12, 14, 30, 859, 294, "12:14:30.859294", "\116\033\086\127\219\132\229\064" ; 23, 36, 43, 131, 669, "23:36:43.131669", "\014\244\080\027\178\192\244\064" ; 23, 0, 33, 533, 700, "23:00:33.533700", "\222\002\009\138\024\057\244\064" ; 5, 40, 3, 602, 400, "05:40:03.602400", "\199\186\184\141\230\236\211\064" ; 1, 37, 4, 139, 707, "01:37:04.139707", "\006\132\214\195\035\192\182\064" ; 0, 52, 0, 113, 246, "00:52:00.113246", "\206\052\097\251\057\096\168\064" ; 14, 22, 24, 689, 495, "14:22:24.689495", "\120\209\087\016\022\068\233\064" ; 10, 27, 27, 845, 999, "10:27:27.845999", "\175\126\108\018\251\097\226\064" ; 23, 7, 23, 769, 867, "23:07:23.769867", "\052\015\096\081\188\082\244\064" ; 8, 9, 35, 674, 831, "08:09:35.674831", "\213\092\110\048\235\175\220\064" ; 23, 1, 33, 931, 317, "23:01:33.931317", "\147\167\172\230\222\060\244\064" ; 14, 46, 28, 153, 618, "14:46:28.153618", "\194\075\112\234\132\248\233\064" ; 13, 23, 11, 375, 942, "13:23:11.375942", "\102\132\183\007\236\135\231\064" ; 19, 20, 1, 293, 943, "19:20:01.293943", "\063\147\253\179\020\254\240\064" ; 18, 3, 14, 945, 514, "18:03:14.945514", "\125\147\166\065\094\188\239\064" ; 19, 0, 37, 926, 513, "19:00:37.926513", "\166\075\255\210\094\181\240\064" ; 23, 12, 28, 742, 491, "23:12:28.742491", "\041\062\062\225\203\101\244\064" ; 2, 45, 44, 857, 539, "02:45:44.857539", "\006\132\214\195\109\108\195\064" ; 11, 31, 54, 906, 940, "11:31:54.906940", "\238\008\167\005\093\069\228\064" ; 3, 44, 53, 915, 432, "03:44:53.915432", "\220\050\224\044\245\090\202\064" ; 19, 18, 18, 980, 264, "19:18:18.980264", "\215\077\041\175\175\247\240\064" ; 6, 58, 54, 534, 771, "06:58:54.534771", "\246\036\176\057\162\139\216\064" ; 9, 55, 56, 656, 792, "09:55:56.656792", "\009\168\112\004\149\117\225\064" ; 17, 44, 44, 536, 695, "17:44:44.536695", "\030\254\154\044\145\049\239\064" ; 12, 1, 33, 168, 957, "12:01:33.168957", "\173\130\024\104\165\035\229\064" ; 20, 46, 48, 828, 916, "20:46:48.828916", "\114\108\061\067\141\067\242\064" ; 6, 52, 3, 521, 304, "06:52:03.521304", "\210\115\011\093\225\036\216\064" ; 11, 34, 7, 74, 182, "11:34:07.074182", "\255\237\178\095\226\085\228\064" ; 1, 13, 22, 84, 108, "01:13:22.084108", "\085\021\026\136\021\050\177\064" ; 3, 16, 24, 49, 259, "03:16:24.049259", "\005\113\030\078\006\004\199\064" ; 18, 51, 24, 427, 286, "18:51:24.427286", "\064\216\041\214\198\146\240\064" ; 7, 18, 36, 695, 458, "07:18:36.695458", "\111\069\098\130\044\179\217\064" ; 11, 21, 8, 291, 244, "11:21:08.291244", "\229\239\222\081\137\244\227\064" ; 22, 55, 13, 799, 456, "22:55:13.799456", "\233\095\146\202\028\037\244\064" ; 16, 23, 9, 80, 515, "16:23:09.080515", "\123\049\148\147\162\205\236\064" ; 17, 41, 40, 152, 930, "17:41:40.152930", "\147\116\205\228\132\026\239\064" ; 5, 58, 37, 806, 239, "05:58:37.806239", "\113\118\107\153\115\003\213\064" ; 0, 18, 58, 51, 494, "00:18:58.051494", "\194\215\215\186\052\200\145\064" ; 16, 5, 2, 584, 408, "16:05:02.584408", "\241\103\120\179\210\069\236\064" ; 7, 10, 9, 767, 675, "07:10:09.767675", "\189\082\150\033\113\052\217\064" ; 17, 27, 57, 989, 435, "17:27:57.989435", "\209\150\115\169\191\179\238\064" ; 0, 33, 1, 828, 958, "00:33:01.828958", "\008\175\093\218\080\247\158\064" ; 0, 42, 24, 131, 611, "00:42:24.131611", "\150\089\132\098\067\224\163\064" ; 17, 11, 12, 81, 660, "17:11:12.081660", "\172\110\245\156\002\054\238\064" ; 8, 26, 48, 587, 811, "08:26:48.587811", "\079\007\178\158\037\178\221\064" ; 2, 40, 33, 168, 173, "02:40:33.168173", "\137\095\177\134\149\208\194\064" ; 23, 27, 39, 458, 867, "23:27:39.458867", "\099\236\132\087\183\158\244\064" ; 4, 54, 29, 38, 548, "04:54:29.038548", "\213\007\146\119\066\065\209\064" ; 10, 21, 18, 316, 540, "10:21:18.316540", "\124\126\024\033\202\051\226\064" ; 23, 28, 45, 908, 805, "23:28:45.908805", "\151\028\119\138\222\162\244\064" ; 9, 0, 30, 906, 159, "09:00:30.906159", "\126\081\130\254\185\171\223\064" ; 8, 26, 4, 861, 611, "08:26:04.861611", "\184\118\162\036\055\167\221\064" ; 0, 22, 56, 848, 850, "00:22:56.848850", "\214\052\239\056\101\131\149\064" ; 20, 57, 34, 434, 901, "20:57:34.434901", "\064\192\090\245\230\107\242\064" ; 19, 3, 3, 832, 302, "19:03:03.832302", "\230\230\027\081\125\190\240\064" ; 16, 41, 57, 744, 120, "16:41:57.744120", "\009\191\212\207\183\090\237\064" ; 0, 47, 45, 923, 303, "00:47:45.923303", "\152\186\043\187\216\099\166\064" ; 23, 59, 56, 517, 899, "23:59:56.517899", "\059\118\080\073\200\023\245\064" ; 8, 8, 9, 411, 549, "08:08:09.411549", "\237\157\209\086\090\154\220\064" ; 3, 3, 33, 154, 630, "03:03:33.154630", "\126\116\234\202\147\130\197\064" ; 16, 24, 5, 996, 700, "16:24:05.996700", "\253\101\247\228\191\212\236\064" ; 15, 9, 3, 821, 617, "15:09:03.821617", "\027\188\175\074\250\161\234\064" ; 10, 50, 15, 387, 120, "10:50:15.387120", "\116\123\073\099\236\012\227\064" ; 23, 7, 53, 651, 935, "23:07:53.651935", "\002\101\083\110\154\084\244\064" ; 5, 14, 24, 969, 407, "05:14:24.969407", "\097\168\195\010\062\108\210\064" ; 0, 2, 24, 821, 765, "00:02:24.821765", "\235\255\028\230\075\026\098\064" ; 10, 38, 3, 71, 134, "10:38:03.071134", "\117\207\186\070\098\177\226\064" ; 9, 43, 5, 245, 398, "09:43:05.245398", "\016\232\076\218\039\021\225\064" ; 8, 32, 4, 168, 755, "08:32:04.168755", "\131\197\225\204\010\001\222\064" ; 3, 2, 47, 0, 466, "03:02:47.000466", "\097\023\069\015\128\107\197\064" ; 1, 53, 0, 804, 875, "01:53:00.804875", "\094\186\073\012\206\124\186\064" ; 18, 48, 25, 519, 641, "18:48:25.519641", "\203\020\115\080\152\135\240\064" ; 22, 17, 53, 863, 351, "22:17:53.863351", "\095\035\073\208\029\153\243\064" ; 11, 56, 4, 982, 602, "11:56:04.982602", "\224\191\121\113\159\250\228\064" ; 10, 25, 45, 560, 16, "10:25:45.560016", "\167\172\166\235\049\085\226\064" ; 20, 32, 18, 920, 662, "20:32:18.920662", "\203\019\008\187\046\013\242\064" ; 3, 47, 27, 189, 71, "03:47:27.189071", "\208\128\122\051\152\167\202\064" ; 6, 22, 49, 751, 860, "06:22:49.751860", "\203\103\121\030\112\110\214\064" ; 8, 31, 52, 126, 800, "08:31:52.126800", "\073\191\125\029\008\254\221\064" ; 13, 30, 37, 916, 64, "13:30:37.916064", "\033\115\101\080\189\191\231\064" ; 9, 22, 6, 408, 142, "09:22:06.408142", "\196\207\127\015\205\119\224\064" ; 18, 56, 37, 589, 901, "18:56:37.589901", "\239\007\060\112\089\166\240\064" ; 12, 14, 31, 771, 676, "12:14:31.771676", "\228\221\145\177\248\132\229\064" ; 3, 23, 36, 435, 483, "03:23:36.435483", "\123\045\232\189\055\220\199\064" ; 21, 53, 43, 975, 782, "21:53:43.975782", "\033\150\205\156\127\062\243\064" ; 23, 25, 30, 349, 896, "23:25:30.349896", "\080\140\044\153\165\150\244\064" ; 13, 13, 42, 510, 15, "13:13:42.510015", "\047\250\010\082\208\064\231\064" ; 11, 16, 4, 329, 700, "11:16:04.329700", "\175\003\231\140\138\206\227\064" ; 18, 40, 48, 14, 924, "18:40:48.014924", "\191\242\032\061\000\107\240\064" ; 19, 42, 36, 539, 310, "19:42:36.539310", "\199\133\003\161\200\082\241\064" ; 11, 2, 45, 86, 317, "11:02:45.086317", "\131\222\027\195\162\106\227\064" ; 20, 27, 46, 492, 890, "20:27:46.492890", "\232\159\224\226\039\252\241\064" ; 10, 43, 20, 383, 837, "10:43:20.383837", "\064\136\100\072\012\217\226\064" ; 19, 37, 15, 283, 902, "19:37:15.283902", "\212\210\220\138\180\062\241\064" ; 12, 0, 25, 51, 309, "12:00:25.051309", "\160\197\082\164\033\027\229\064" ; 20, 19, 25, 731, 134, "20:19:25.731134", "\176\144\185\178\219\220\241\064" ; 14, 6, 24, 700, 834, "14:06:24.700834", "\189\108\059\109\022\204\232\064" ; 16, 48, 36, 763, 550, "16:48:36.763550", "\219\104\000\111\152\140\237\064" ; 8, 53, 35, 949, 999, "08:53:35.949999", "\015\155\200\204\252\067\223\064" ; 12, 20, 20, 882, 755, "12:20:20.882755", "\236\105\135\063\156\176\229\064" ; 21, 1, 52, 899, 925, "21:01:52.899925", "\190\193\023\102\014\124\242\064" ; 7, 56, 32, 810, 38, "07:56:32.810038", "\161\159\169\215\051\236\219\064" ; 16, 40, 14, 233, 730, "16:40:14.233730", "\067\086\183\122\199\077\237\064" ; 22, 4, 10, 217, 169, "22:04:10.217169", "\140\051\134\121\163\101\243\064" ; 11, 45, 1, 357, 11, "11:45:01.357011", "\042\085\162\108\171\167\228\064" ; 0, 30, 13, 412, 25, "00:30:13.412025", "\138\176\225\233\165\085\156\064" ; 8, 22, 29, 979, 619, "08:22:29.979619", "\226\227\019\178\126\113\221\064" ; 18, 34, 58, 289, 410, "18:34:58.289410", "\082\097\108\161\036\085\240\064" ; 23, 48, 10, 612, 742, "23:48:10.612742", "\046\142\202\205\169\235\244\064" ; 8, 56, 9, 199, 380, "08:56:09.199380", "\223\084\164\194\076\106\223\064" ; 13, 26, 17, 383, 11, "13:26:17.383011", "\224\072\160\065\044\159\231\064" ; 6, 20, 53, 748, 51, "06:20:53.748051", "\047\077\017\224\111\081\214\064" ; 23, 44, 50, 331, 52, "23:44:50.331052", "\149\046\253\075\037\223\244\064" ; 8, 29, 2, 347, 446, "08:29:02.347446", "\200\037\142\060\150\211\221\064" ; 12, 12, 30, 277, 527, "12:12:30.277527", "\152\077\128\225\200\117\229\064" ; 23, 10, 21, 993, 28, "23:10:21.993028", "\000\084\113\227\223\093\244\064" ; 13, 55, 32, 904, 124, "13:55:32.904124", "\113\116\149\238\156\122\232\064" ; 12, 34, 54, 78, 666, "12:34:54.078666", "\042\143\110\132\194\029\230\064" ; 16, 47, 53, 749, 115, "16:47:53.749115", "\063\005\192\248\055\135\237\064" ; 19, 39, 47, 339, 475, "19:39:47.339475", "\109\086\125\110\053\072\241\064" ; 23, 26, 25, 59, 400, "23:26:25.059400", "\022\106\077\243\016\154\244\064" ; 14, 51, 39, 31, 343, "14:51:39.031343", "\255\008\195\000\097\031\234\064" ; 11, 4, 28, 526, 374, "11:04:28.526374", "\111\073\014\216\144\119\227\064" ; 14, 55, 42, 444, 882, "14:55:42.444882", "\019\045\121\060\206\061\234\064" ; 12, 49, 43, 550, 344, "12:49:43.550344", "\050\005\107\156\241\140\230\064" ; 1, 23, 18, 160, 216, "01:23:18.160216", "\076\112\234\003\041\134\179\064" ; 7, 25, 37, 890, 738, "07:25:37.890738", "\211\244\217\001\121\028\218\064" ; 18, 11, 40, 379, 179, "18:11:40.379179", "\139\255\059\034\140\251\239\064" ; 2, 37, 17, 459, 146, "02:37:17.459146", "\012\207\075\197\186\110\194\064" ; 11, 53, 28, 11, 462, "11:53:28.011462", "\101\142\229\093\000\231\228\064" ; 14, 18, 52, 531, 190, "14:18:52.531190", "\191\043\130\255\144\041\233\064" ; 14, 54, 15, 592, 47, "14:54:15.592047", "\214\140\012\242\242\050\234\064" ; 22, 18, 49, 772, 253, "22:18:49.772253", "\052\246\037\091\156\156\243\064" ; 5, 41, 6, 208, 601, "05:41:06.208601", "\058\002\184\089\141\252\211\064" ; 23, 23, 45, 617, 32, "23:23:45.617032", "\073\242\092\223\025\144\244\064" ; 9, 26, 49, 502, 279, "09:26:49.502279", "\207\104\171\018\048\155\224\064" ; 13, 0, 39, 703, 51, "13:00:39.703051", "\142\207\100\127\246\222\230\064" ; 19, 30, 8, 296, 137, "19:30:08.296137", "\162\038\250\188\004\036\241\064" ; 11, 1, 2, 984, 539, "11:01:02.984539", "\212\238\087\129\223\093\227\064" ; 5, 13, 27, 869, 152, "05:13:27.869152", "\208\181\047\160\247\093\210\064" ; 0, 4, 17, 475, 85, "00:04:17.475085", "\032\157\186\242\153\023\112\064" ; 3, 25, 35, 323, 288, "03:25:35.323288", "\152\077\128\097\169\023\200\064" ; 22, 0, 0, 59, 687, "22:00:00.059687", "\016\091\122\244\000\086\243\064" ; 12, 5, 31, 28, 822, "12:05:31.028822", "\109\029\028\236\096\065\229\064" ; 21, 22, 19, 993, 239, "21:22:19.993239", "\226\147\078\228\191\200\242\064" ; 22, 0, 17, 135, 557, "22:00:17.135557", "\028\209\061\043\018\087\243\064" ; 5, 23, 31, 420, 213, "05:23:31.420213", "\022\017\197\228\218\244\210\064" ; 7, 24, 27, 554, 314, "07:24:27.554314", "\110\109\225\121\227\010\218\064" ; 11, 38, 9, 990, 419, "11:38:09.990419", "\203\047\131\177\063\116\228\064" ; 7, 17, 2, 297, 678, "07:17:02.297678", "\175\006\040\013\147\155\217\064" ; 20, 42, 30, 810, 317, "20:42:30.810317", "\102\245\014\247\108\051\242\064" ; 3, 17, 42, 727, 870, "03:17:42.727870", "\223\026\216\042\093\043\199\064" ; 7, 2, 20, 218, 834, "07:02:20.218834", "\080\082\096\001\014\191\216\064" ; 16, 28, 51, 642, 168, "16:28:51.642168", "\209\231\163\140\116\248\236\064" ; 20, 47, 45, 139, 321, "20:47:45.139321", "\042\168\168\058\018\071\242\064" ; 16, 13, 51, 39, 91, "16:13:51.039091", "\210\196\059\064\225\135\236\064" ; 22, 30, 20, 640, 872, "22:30:20.640872", "\143\255\002\065\202\199\243\064" ; 2, 51, 15, 166, 979, "02:51:15.166979", "\015\096\145\095\149\017\196\064" ; 14, 32, 51, 987, 145, "14:32:51.987145", "\109\028\177\150\127\146\233\064" ; 4, 8, 30, 585, 461, "04:08:30.585461", "\010\212\098\240\074\031\205\064" ; 22, 15, 33, 76, 297, "22:15:33.076297", "\253\051\131\056\081\144\243\064" ; 17, 24, 55, 347, 973, "17:24:55.347973", "\221\069\152\034\235\156\238\064" ; 1, 0, 5, 628, 604, "01:00:05.628604", "\069\044\098\216\065\043\172\064" ; 19, 39, 46, 965, 871, "19:39:46.965871", "\082\038\053\116\047\072\241\064" ; 2, 26, 19, 827, 606, "02:26:19.827606", "\252\079\254\238\233\037\193\064" ; 3, 35, 49, 666, 719, "03:35:49.666719", "\079\086\012\087\213\074\201\064" ; 22, 34, 45, 294, 769, "22:34:45.294769", "\238\178\095\183\084\216\243\064" ; 13, 20, 39, 360, 466, "13:20:39.360466", "\042\254\239\136\235\116\231\064" ; 19, 13, 2, 468, 414, "19:13:02.468414", "\175\173\159\126\231\227\240\064" ; 8, 30, 52, 168, 810, "08:30:52.168810", "\080\117\200\205\010\239\221\064" ; 0, 23, 18, 267, 433, "00:23:18.267433", "\124\211\244\217\017\217\149\064" ; 18, 50, 11, 343, 615, "18:50:11.343615", "\054\113\114\127\053\142\240\064" ; 22, 6, 42, 682, 572, "22:06:42.682572", "\019\158\208\235\042\111\243\064" ; 14, 9, 36, 948, 252, "14:09:36.948252", "\011\148\020\088\030\228\232\064" ; 7, 34, 24, 682, 770, "07:34:24.682770", "\044\241\128\178\043\160\218\064" ; 15, 41, 12, 492, 782, "15:41:12.492782", "\194\193\222\196\015\147\235\064" ; 3, 23, 32, 180, 551, "03:23:32.180551", "\033\144\075\028\023\218\199\064" ; 12, 48, 14, 333, 695, "12:48:14.333695", "\251\034\161\173\202\129\230\064" ; 13, 57, 45, 616, 888, "13:57:45.616888", "\042\231\139\189\051\139\232\064" ; 1, 5, 57, 593, 739, "01:05:57.593739", "\184\230\142\254\047\235\174\064" ; 1, 13, 49, 987, 122, "01:13:49.987122", "\042\003\007\180\252\077\177\064" ; 23, 18, 2, 875, 146, "23:18:02.875146", "\148\023\153\000\174\122\244\064" ; 9, 11, 18, 458, 773, "09:11:18.458773", "\233\182\068\174\206\038\224\064" ; 7, 23, 11, 315, 790, "07:23:11.315790", "\153\066\231\053\212\247\217\064" ; 17, 48, 10, 986, 19, "17:48:10.986019", "\199\183\119\141\095\075\239\064" ; 4, 56, 37, 680, 447, "04:56:37.680447", "\234\146\113\140\107\097\209\064" ; 18, 50, 58, 309, 837, "18:50:58.309837", "\097\164\023\245\036\145\240\064" ; 14, 50, 35, 998, 182, "14:50:35.998182", "\175\096\027\241\127\023\234\064" ; 5, 13, 8, 370, 949, "05:13:08.370949", "\223\223\160\189\023\089\210\064" ; 3, 24, 56, 480, 444, "03:24:56.480444", "\199\097\048\127\061\004\200\064" ; 8, 34, 54, 786, 340, "08:34:54.786340", "\226\001\101\083\178\043\222\064" ; 2, 26, 48, 919, 523, "02:26:48.919523", "\118\254\237\178\117\052\193\064" ; 8, 41, 56, 323, 429, "08:41:56.323429", "\101\140\015\179\020\149\222\064" ; 21, 15, 34, 772, 898, "21:15:34.772898", "\018\075\202\093\108\175\242\064" ; 2, 23, 57, 822, 912, "02:23:57.822912", "\190\047\046\085\233\222\192\064" ; 5, 24, 25, 354, 580, "05:24:25.354580", "\244\079\112\177\086\002\211\064" ; 9, 57, 57, 566, 906, "09:57:57.566906", "\061\013\024\036\178\132\225\064" ; 23, 41, 25, 45, 71, "23:41:25.045071", "\112\094\156\184\080\210\244\064" ; 23, 12, 26, 612, 642, "23:12:26.612642", "\162\178\097\205\169\101\244\064" ; 0, 11, 6, 794, 518, "00:11:06.794518", "\171\208\064\044\091\214\132\064" ; 11, 6, 23, 26, 262, "11:06:23.026262", "\228\103\035\215\224\133\227\064" ; 9, 58, 39, 728, 735, "09:58:39.728735", "\015\016\204\081\247\137\225\064" ; 1, 41, 53, 539, 501, "01:41:53.539501", "\041\207\188\028\138\225\183\064" ; 21, 47, 8, 336, 303, "21:47:08.336303", "\040\065\127\097\197\037\243\064" ; 8, 29, 54, 497, 554, "08:29:54.497554", "\127\187\236\215\159\224\221\064" ; 12, 5, 23, 359, 997, "12:05:23.359997", "\181\109\024\133\107\064\229\064" ; 18, 44, 20, 72, 632, "18:44:20.072632", "\010\044\128\041\065\120\240\064" ; 15, 45, 21, 756, 497, "15:45:21.756497", "\081\050\057\053\056\178\235\064" ; 11, 15, 42, 608, 929, "11:15:42.608929", "\147\171\088\124\211\203\227\064" ; 18, 8, 23, 954, 55, "18:08:23.954055", "\242\089\158\135\254\226\239\064" ; 9, 5, 18, 641, 451, "09:05:18.641451", "\191\126\136\013\169\243\223\064" ; 22, 5, 3, 576, 399, "22:05:03.576399", "\103\040\238\056\249\104\243\064" ; 14, 14, 30, 597, 822, "14:14:30.597822", "\091\154\091\033\211\008\233\064" ; 23, 47, 30, 293, 511, "23:47:30.293511", "\033\151\056\178\036\233\244\064" ; 13, 43, 15, 744, 344, "13:43:15.744344", "\031\130\170\209\119\030\232\064" ; 19, 59, 18, 502, 927, "19:59:18.502927", "\148\046\253\011\104\145\241\064" ; 13, 36, 42, 115, 593, "13:36:42.115593", "\084\023\240\178\067\237\231\064" ; 15, 23, 19, 805, 324, "15:23:19.805324", "\086\214\054\197\249\012\235\064" ; 8, 54, 12, 598, 412, "08:54:12.598412", "\099\216\097\076\038\077\223\064" ; 9, 25, 18, 737, 495, "09:25:18.737495", "\063\029\143\153\215\143\224\064" ; 21, 24, 36, 811, 191, "21:24:36.811191", "\253\105\163\250\076\209\242\064" ; 11, 14, 39, 295, 292, "11:14:39.295292", "\088\053\008\115\233\195\227\064" ; 12, 45, 25, 294, 0, "12:45:25.294000", "\033\176\114\104\169\108\230\064" ; 7, 47, 54, 898, 603, "07:47:54.898603", "\070\040\182\130\185\106\219\064" ; 18, 47, 14, 965, 202, "18:47:14.965202", "\000\167\119\113\047\131\240\064" ; 9, 49, 27, 258, 228, "09:49:27.258228", "\221\093\103\067\232\068\225\064" ; 11, 9, 44, 82, 431, "11:09:44.082431", "\038\086\070\163\002\159\227\064" ; 1, 48, 27, 404, 347, "01:48:27.404347", "\061\245\072\131\103\107\185\064" ; 18, 42, 20, 222, 935, "18:42:20.222935", "\098\074\036\145\195\112\240\064" ; 10, 22, 32, 556, 929, "10:22:32.556929", "\038\196\092\210\017\061\226\064" ; 13, 30, 49, 299, 890, "13:30:49.299890", "\205\233\178\152\041\193\231\064" ; 0, 16, 30, 221, 557, "00:16:30.221557", "\153\041\173\191\197\241\142\064" ; 0, 20, 40, 478, 117, "00:20:40.478117", "\166\186\128\151\233\097\147\064" ; 16, 11, 0, 473, 708, "16:11:00.473708", "\251\173\157\040\143\114\236\064" ; 3, 48, 48, 909, 114, "03:48:48.909114", "\043\249\216\093\116\208\202\064" ; 17, 27, 27, 987, 371, "17:27:27.987371", "\065\017\139\152\255\175\238\064" ; 8, 42, 41, 175, 670, "08:42:41.175670", "\057\098\045\062\075\160\222\064" ; 16, 32, 12, 606, 669, "16:32:12.606669", "\080\027\213\105\147\017\237\064" ; 10, 51, 11, 786, 559, "10:51:11.786559", "\172\199\125\043\249\019\227\064" ; 21, 35, 37, 121, 566, "21:35:37.121566", "\165\048\239\241\145\250\242\064" ; 5, 56, 9, 233, 447, "05:56:09.233447", "\150\175\203\240\078\222\212\064" ; 21, 26, 15, 309, 108, "21:26:15.309108", "\238\058\027\242\116\215\242\064" ; 9, 0, 44, 425, 53, "09:00:44.425053", "\132\127\017\052\027\175\223\064" ; 10, 0, 3, 459, 991, "10:00:03.459991", "\175\011\063\184\110\148\225\064" ; 19, 45, 15, 474, 403, "19:45:15.474403", "\162\153\039\151\183\092\241\064" ; 12, 36, 0, 0, 94, "12:36:00.000094", "\222\033\197\000\000\038\230\064" ; 12, 35, 20, 366, 660, "12:35:20.366660", "\152\192\173\187\011\033\230\064" ; 7, 17, 39, 396, 824, "07:17:39.396824", "\145\125\144\101\217\164\217\064" ; 7, 37, 50, 674, 450, "07:37:50.674450", "\050\085\048\042\171\211\218\064" ; 23, 42, 43, 218, 167, "23:42:43.218167", "\033\174\156\125\051\215\244\064" ; 3, 46, 1, 272, 786, "03:46:01.272786", "\104\210\166\234\162\124\202\064" ; 21, 46, 55, 819, 427, "21:46:55.819427", "\104\124\095\028\253\036\243\064" ; 15, 35, 14, 876, 665, "15:35:14.876665", "\017\194\163\013\092\102\235\064" ; 21, 25, 16, 237, 921, "21:25:16.237921", "\032\064\134\206\195\211\242\064" ; 12, 20, 41, 35, 535, "12:20:41.035535", "\220\075\026\035\033\179\229\064" ; 20, 10, 3, 251, 63, "20:10:03.251063", "\228\162\090\004\180\185\241\064" ; 16, 55, 59, 527, 248, "16:55:59.527248", "\156\050\055\223\240\195\237\064" ; 18, 3, 57, 486, 302, "18:03:57.486302", "\063\054\201\143\175\193\239\064" ; 3, 38, 2, 335, 283, "03:38:02.335283", "\243\167\141\234\042\141\201\064" ; 15, 41, 28, 675, 872, "15:41:28.675872", "\009\081\190\160\021\149\235\064" ; 17, 21, 11, 140, 298, "17:21:11.140298", "\054\059\082\125\228\128\238\064" ; 20, 8, 18, 754, 576, "20:08:18.754576", "\166\072\190\018\044\179\241\064" ; 2, 6, 5, 762, 65, "02:06:05.762065", "\109\028\177\022\195\141\189\064" ; 3, 16, 57, 539, 679, "03:16:57.539679", "\172\147\051\020\197\020\199\064" ; 10, 30, 44, 112, 698, "10:30:44.112698", "\011\214\056\155\131\122\226\064" ; 6, 19, 1, 219, 823, "06:19:01.219823", "\250\124\148\017\078\053\214\064" ; 14, 52, 8, 326, 738, "14:52:08.326738", "\012\064\163\116\010\035\234\064" ; 11, 49, 13, 655, 393, "11:49:13.655393", "\161\189\250\248\052\199\228\064" ; 1, 12, 56, 772, 405, "01:12:56.772405", "\068\134\085\188\197\024\177\064" ; 20, 26, 30, 769, 334, "20:26:30.769334", "\027\043\049\079\108\247\241\064" ; 12, 3, 37, 740, 891, "12:03:37.740891", "\221\010\097\181\055\051\229\064" ; 7, 58, 0, 345, 418, "07:58:00.345418", "\093\025\084\027\022\002\220\064" ; 21, 25, 18, 211, 116, "21:25:18.211116", "\186\043\187\096\227\211\242\064" ; 8, 2, 33, 265, 250, "08:02:33.265250", "\209\034\219\249\080\070\220\064" ; 22, 8, 45, 473, 576, "22:08:45.473576", "\131\109\196\147\215\118\243\064" ; 13, 5, 33, 997, 565, "13:05:33.997565", "\085\111\013\236\191\003\231\064" ; 11, 57, 0, 680, 599, "11:57:00.680599", "\214\141\119\199\149\001\229\064" ; 13, 35, 40, 481, 854, "13:35:40.481854", "\110\020\089\107\143\229\231\064" ; 0, 58, 3, 351, 947, "00:58:03.351947", "\218\173\101\050\180\054\171\064" ; 12, 52, 18, 59, 92, "12:52:18.059092", "\239\231\020\228\065\160\230\064" ; 17, 5, 20, 761, 388, "17:05:20.761388", "\242\093\074\093\024\010\238\064" ; 22, 1, 3, 139, 300, "22:01:03.139300", "\005\163\146\058\242\089\243\064" ; 7, 7, 43, 660, 717, "07:07:43.660717", "\186\244\047\073\234\015\217\064" ; 0, 16, 28, 585, 372, "00:16:28.585372", "\244\223\131\215\174\228\142\064" ; 1, 31, 29, 58, 21, "01:31:29.058021", "\123\217\118\218\014\113\181\064" ; 11, 15, 56, 786, 439, "11:15:56.786439", "\042\031\130\042\153\205\227\064" ; 7, 5, 21, 182, 24, "07:05:21.182024", "\198\253\071\166\075\236\216\064" ; 6, 32, 47, 722, 979, "06:32:47.722979", "\045\182\073\069\238\003\215\064" ; 10, 8, 19, 437, 463, "10:08:19.437463", "\198\103\178\255\109\210\225\064" ; 3, 18, 58, 473, 65, "03:18:58.473065", "\241\215\100\141\060\081\199\064" ; 10, 45, 52, 258, 397, "10:45:52.258397", "\013\201\201\068\008\236\226\064" ; 4, 47, 19, 773, 478, "04:47:19.773478", "\140\222\169\128\241\213\208\064" ; 22, 53, 46, 616, 954, "22:53:46.616954", "\082\040\011\223\169\031\244\064" ; 11, 49, 49, 208, 242, "11:49:49.208242", "\117\032\235\169\166\203\228\064" ; 9, 21, 45, 780, 693, "09:21:45.780693", "\231\226\111\251\056\117\224\064" ; 11, 42, 51, 542, 944, "11:42:51.542944", "\114\024\204\095\113\151\228\064" ; 14, 19, 56, 499, 348, "14:19:56.499348", "\043\168\168\250\143\049\233\064" ; 20, 58, 6, 321, 742, "20:58:06.321742", "\124\240\218\037\229\109\242\064" ; 6, 10, 30, 233, 661, "06:10:30.233661", "\086\068\077\244\142\181\213\064" ; 15, 28, 16, 402, 460, "15:28:16.402460", "\063\203\243\224\012\050\235\064" ; 23, 23, 12, 291, 752, "23:23:12.291752", "\041\037\004\171\004\142\244\064" ; 1, 42, 21, 898, 914, "01:42:21.898914", "\235\087\058\031\230\253\183\064" ; 4, 58, 15, 158, 738, "04:58:15.158738", "\168\109\195\040\202\121\209\064" ; 11, 58, 34, 821, 211, "11:58:34.821211", "\132\074\092\071\090\013\229\064" ; 5, 12, 34, 647, 955, "05:12:34.647955", "\146\063\024\120\169\080\210\064" ; 4, 53, 43, 751, 78, "04:53:43.751078", "\176\117\169\017\240\053\209\064" ; 11, 50, 4, 686, 964, "11:50:04.686964", "\049\237\155\251\149\205\228\064" ; 2, 31, 57, 763, 718, "02:31:57.763718", "\175\236\130\193\225\206\193\064" ; 1, 2, 50, 448, 792, "01:02:50.448792", "\105\165\016\200\229\116\173\064" ; 8, 28, 10, 926, 584, "08:28:10.926584", "\064\250\038\077\187\198\221\064" ; 18, 4, 39, 246, 79, "18:04:39.246079", "\039\017\225\223\231\198\239\064" ; 11, 18, 52, 717, 34, "11:18:52.717034", "\131\073\241\241\150\227\227\064" ; 21, 18, 4, 608, 861, "21:18:04.608861", "\044\008\229\189\201\184\242\064" ; 18, 43, 33, 645, 208, "18:43:33.645208", "\178\159\197\082\090\117\240\064" ; 22, 53, 51, 656, 83, "22:53:51.656083", "\072\227\080\127\250\031\244\064" ; 6, 33, 8, 864, 985, "06:33:08.864985", "\162\011\234\091\055\009\215\064" ; 19, 56, 23, 914, 462, "19:56:23.914462", "\247\231\162\161\126\134\241\064" ; 7, 44, 38, 80, 790, "07:44:38.080790", "\246\209\169\043\133\057\219\064" ; 20, 46, 28, 540, 270, "20:46:28.540270", "\208\039\242\164\072\066\242\064" ; 0, 55, 29, 961, 52, "00:55:29.961052", "\130\251\001\015\236\003\170\064" ; 8, 27, 6, 946, 729, "08:27:06.946729", "\075\059\053\151\188\182\221\064" ; 19, 2, 9, 815, 497, "19:02:09.815497", "\016\149\070\012\029\187\240\064" ; 21, 26, 54, 389, 292, "21:26:54.389292", "\137\063\138\058\230\217\242\064" ; 6, 29, 20, 481, 824, "06:29:20.481824", "\155\084\052\214\030\208\214\064" ; 6, 5, 35, 386, 131, "06:05:35.386131", "\062\204\094\182\216\107\213\064" ; 9, 42, 48, 823, 234, "09:42:48.823234", "\094\212\238\087\026\019\225\064" ; 6, 26, 21, 830, 208, "06:26:21.830208", "\057\188\032\034\117\163\214\064" ; 20, 43, 35, 360, 71, "20:43:35.360071", "\020\207\217\194\117\055\242\064" ; 9, 34, 23, 946, 180, "09:34:23.946180", "\133\071\027\071\254\211\224\064" ; 23, 57, 51, 337, 489, "23:57:51.337489", "\156\221\090\102\245\015\245\064" ; 12, 13, 11, 172, 868, "12:13:11.172868", "\209\120\034\136\229\122\229\064" ; 18, 17, 34, 879, 190, "18:17:34.879190", "\144\136\041\017\238\019\240\064" ; 6, 26, 52, 128, 65, "06:26:52.128065", "\177\138\055\050\008\171\214\064" ; 12, 7, 31, 712, 4, "12:07:31.712004", "\212\156\188\200\118\080\229\064" ; 9, 9, 7, 701, 338, "09:09:07.701338", "\174\099\092\113\118\022\224\064" ; 12, 49, 12, 82, 914, "12:49:12.082914", "\204\066\059\167\002\137\230\064" ; 18, 38, 25, 853, 644, "18:38:25.853644", "\103\156\134\168\029\098\240\064" ; 3, 24, 6, 553, 495, "03:24:06.553495", "\192\149\236\216\070\235\199\064" ; 20, 22, 20, 241, 443, "20:22:20.241443", "\205\085\243\220\195\231\241\064" ; 16, 37, 34, 108, 143, "16:37:34.108143", "\009\079\232\117\195\057\237\064" ; 1, 42, 10, 328, 663, "01:42:10.328663", "\104\036\066\035\084\242\183\064" ; 5, 49, 41, 497, 452, "05:49:41.497452", "\213\233\064\214\095\125\212\064" ; 10, 59, 50, 589, 37, "10:59:50.589037", "\100\031\100\217\210\084\227\064" ; 4, 34, 27, 145, 40, "04:34:27.145040", "\039\218\085\072\201\020\208\064" ; 6, 13, 22, 127, 750, "06:13:22.127750", "\004\086\014\045\136\224\213\064" ; 5, 37, 48, 772, 523, "05:37:48.772523", "\026\079\004\113\049\203\211\064" ; 5, 33, 51, 144, 876, "05:33:51.144876", "\126\252\165\069\201\143\211\064" ; 7, 38, 59, 170, 316, "07:38:59.170316", "\127\020\117\230\202\228\218\064" ; 5, 17, 6, 452, 246, "05:17:06.452246", "\240\052\153\241\156\148\210\064" ; 17, 47, 17, 333, 34, "17:47:17.333034", "\078\235\054\168\170\068\239\064" ; 16, 49, 34, 841, 128, "16:49:34.841128", "\120\068\133\234\218\147\237\064" ; 13, 25, 23, 452, 195, "13:25:23.452195", "\013\166\097\120\110\152\231\064" ; 8, 48, 18, 429, 209, "08:48:18.429209", "\138\006\041\120\155\244\222\064" ; 3, 6, 52, 917, 313, "03:06:52.917313", "\153\043\131\106\117\230\197\064" ; 21, 26, 31, 73, 855, "21:26:31.073855", "\155\148\130\046\113\216\242\064" ; 4, 15, 57, 579, 520, "04:15:57.579520", "\176\027\182\045\202\254\205\064" ; 22, 17, 39, 427, 636, "22:17:39.427636", "\169\216\152\215\054\152\243\064" ; 17, 59, 46, 960, 507, "17:59:46.960507", "\018\045\121\188\094\162\239\064" ; 15, 21, 10, 828, 10, "15:21:10.828010", "\217\211\014\127\218\252\234\064" ; 10, 23, 50, 771, 1, "10:23:50.771001", "\006\074\010\172\216\070\226\064" ; 13, 10, 16, 227, 524, "13:10:16.227524", "\098\105\224\071\007\039\231\064" ; 6, 11, 53, 64, 42, "06:11:53.064042", "\228\157\067\025\068\202\213\064" ; 21, 8, 30, 865, 921, "21:08:30.865921", "\127\250\207\218\237\148\242\064" ; 20, 40, 26, 95, 809, "20:40:26.095809", "\155\004\111\136\161\043\242\064" ; 20, 1, 42, 954, 329, "20:01:42.954329", "\074\124\238\068\111\154\241\064" ; 0, 53, 44, 872, 831, "00:53:44.872831", "\222\111\180\227\190\049\169\064" ; 23, 46, 45, 123, 962, "23:46:45.123962", "\000\148\191\251\081\230\244\064" ; 17, 15, 54, 789, 967, "17:15:54.789967", "\189\223\104\071\089\089\238\064" ; 18, 34, 27, 547, 99, "18:34:27.547099", "\139\225\234\192\056\083\240\064" ; 13, 19, 44, 940, 862, "13:19:44.940862", "\002\160\138\027\030\110\231\064" ; 17, 14, 11, 900, 779, "17:14:11.900779", "\062\123\046\211\124\076\238\064" ; 9, 28, 13, 721, 136, "09:28:13.721136", "\255\205\139\019\183\165\224\064" ; 19, 29, 24, 471, 783, "19:29:24.471783", "\189\084\108\140\071\033\241\064" ; 18, 18, 35, 709, 634, "18:18:35.709634", "\098\046\169\090\187\023\240\064" ; 10, 42, 7, 270, 686, "10:42:07.270686", "\175\175\117\169\232\207\226\064" ; 8, 2, 26, 808, 651, "08:02:26.808651", "\184\031\240\192\179\068\220\064" ; 10, 59, 40, 63, 626, "10:59:40.063626", "\166\100\057\009\130\083\227\064" ; 7, 45, 7, 460, 1, "07:45:07.460001", "\200\008\168\112\221\064\219\064" ; 13, 54, 41, 106, 177, "13:54:41.106177", "\211\078\205\101\035\116\232\064" ; 7, 23, 38, 356, 418, "07:23:38.356418", "\109\113\141\207\150\254\217\064" ; 12, 51, 47, 110, 581, "12:51:47.110581", "\082\042\225\137\099\156\230\064" ; 2, 49, 33, 125, 201, "02:49:33.125201", "\055\028\150\006\144\222\195\064" ; 21, 55, 47, 352, 302, "21:55:47.352302", "\005\108\007\163\053\070\243\064" ; 19, 15, 28, 381, 577, "19:15:28.381577", "\254\123\240\026\006\237\240\064" ; 18, 5, 12, 277, 952, "18:05:12.277952", "\188\151\251\228\008\203\239\064" ; 14, 46, 40, 902, 374, "14:46:40.902374", "\089\112\063\224\028\250\233\064" ; 23, 42, 24, 988, 295, "23:42:24.988295", "\253\106\014\208\015\214\244\064" ; 7, 10, 49, 799, 109, "07:10:49.799109", "\060\019\154\036\115\062\217\064" ; 15, 2, 14, 4, 144, "15:02:14.004144", "\015\153\242\033\192\110\234\064" ; 16, 50, 56, 323, 278, "16:50:56.323278", "\176\026\075\088\010\158\237\064" ; 11, 8, 43, 93, 128, "11:08:43.093128", "\075\146\231\250\098\151\227\064" ; 15, 28, 45, 496, 452, "15:28:45.496452", "\001\078\239\226\175\053\235\064" ; 17, 35, 1, 983, 273, "17:35:01.983273", "\065\240\248\118\191\232\238\064" ; 11, 27, 10, 210, 157, "11:27:10.210157", "\065\044\155\185\198\033\228\064" ; 6, 32, 3, 922, 177, "06:32:03.922177", "\008\174\242\004\251\248\214\064" ; 20, 30, 32, 139, 819, "20:30:32.139819", "\005\217\178\060\130\006\242\064" ; 22, 38, 13, 678, 356, "22:38:13.678356", "\049\210\139\218\090\229\243\064" ; 5, 39, 46, 536, 301, "05:39:46.536301", "\244\109\193\082\162\232\211\064" ; 14, 38, 48, 538, 708, "14:38:48.538708", "\067\143\024\061\017\191\233\064" ; 13, 58, 13, 686, 138, "13:58:13.686138", "\210\173\215\244\181\142\232\064" ; 7, 37, 25, 921, 280, "07:37:25.921280", "\157\099\064\246\122\205\218\064" ; 15, 7, 10, 346, 558, "15:07:10.346558", "\133\205\000\023\203\147\234\064" ; 23, 0, 51, 329, 827, "23:00:51.329827", "\037\173\248\070\053\058\244\064" ; 10, 49, 22, 277, 597, "10:49:22.277597", "\143\026\019\226\072\006\227\064" ; 11, 54, 7, 171, 814, "11:54:07.171814", "\224\018\128\127\229\235\228\064" ; 18, 27, 53, 137, 592, "18:27:53.137592", "\067\171\147\051\146\058\240\064" ; 10, 7, 1, 203, 16, "10:07:01.203016", "\018\105\027\127\166\200\225\064" ; 21, 11, 52, 493, 585, "21:11:52.493585", "\141\098\185\229\135\161\242\064" ; 5, 24, 16, 923, 47, "05:24:16.923047", "\107\185\051\019\059\000\211\064" ; 22, 56, 48, 499, 566, "22:56:48.499566", "\003\235\056\254\007\043\244\064" ; 11, 54, 46, 835, 215, "11:54:46.835215", "\196\206\020\186\218\240\228\064" ; 17, 7, 6, 378, 131, "17:07:06.378131", "\211\046\166\025\076\023\238\064" ; 19, 20, 30, 405, 530, "19:20:30.405530", "\121\006\013\125\230\255\240\064" ; 22, 7, 15, 481, 201, "22:07:15.481201", "\221\209\255\178\055\113\243\064" ; 20, 57, 38, 453, 184, "20:57:38.453184", "\177\221\061\064\039\108\242\064" ; 12, 11, 12, 186, 834, "12:11:12.186834", "\249\075\139\250\005\108\229\064" ; 21, 31, 42, 551, 170, "21:31:42.551170", "\073\162\151\209\232\235\242\064" ; 15, 29, 24, 112, 483, "15:29:24.112483", "\204\242\117\153\131\058\235\064" ; 5, 21, 27, 680, 440, "05:21:27.680440", "\185\054\084\140\235\213\210\064" ; 11, 41, 44, 849, 339, "11:41:44.849339", "\135\251\200\045\027\143\228\064" ; 4, 31, 38, 459, 544, "04:31:38.459544", "\138\121\086\210\058\213\207\064" ; 16, 21, 32, 726, 454, "16:21:32.726454", "\130\117\028\063\151\193\236\064" ; 5, 23, 7, 285, 314, "05:23:07.285314", "\198\166\149\066\210\238\210\064" ; 0, 26, 59, 813, 591, "00:26:59.813591", "\072\197\255\029\065\079\153\064" ; 20, 54, 20, 599, 267, "20:54:20.599267", "\105\254\152\150\201\095\242\064" ; 6, 48, 23, 714, 533, "06:48:23.714533", "\186\158\232\186\237\237\215\064" ; 6, 38, 38, 846, 37, "06:38:38.846037", "\142\095\120\037\182\091\215\064" ; 18, 13, 28, 510, 732, "18:13:28.510732", "\080\081\245\043\136\004\240\064" ; 6, 48, 1, 941, 952, "06:48:01.941952", "\153\010\241\072\124\232\215\064" ; 20, 47, 49, 510, 372, "20:47:49.510372", "\140\212\123\042\088\071\242\064" ; 14, 53, 8, 391, 588, "14:53:08.391588", "\177\142\227\135\140\042\234\064" ; 23, 53, 11, 566, 998, "23:53:11.566998", "\175\126\108\018\121\254\244\064" ; 19, 2, 41, 90, 311, "19:02:41.090311", "\119\242\233\113\017\189\240\064" ; 20, 4, 29, 127, 173, "20:04:29.127173", "\062\142\230\008\210\164\241\064" ; 7, 28, 31, 943, 62, "07:28:31.943062", "\006\184\032\091\252\071\218\064" ; 1, 59, 0, 648, 456, "01:59:00.648456", "\229\096\054\001\166\228\187\064" ; 21, 30, 1, 513, 492, "21:30:01.513492", "\045\099\067\055\152\229\242\064" ; 8, 20, 25, 165, 372, "08:20:25.165372", "\235\112\116\149\074\082\221\064" ; 9, 29, 2, 897, 203, "09:29:02.897203", "\220\016\227\181\220\171\224\064" ; 4, 53, 25, 947, 984, "04:53:25.947984", "\072\021\197\171\124\049\209\064" ; 17, 23, 53, 282, 633, "17:23:53.282633", "\121\092\084\011\041\149\238\064" ; 23, 34, 22, 345, 624, "23:34:22.345624", "\011\008\173\135\229\183\244\064" ; 7, 27, 49, 750, 326, "07:27:49.750326", "\214\087\087\005\112\061\218\064" ; 14, 43, 1, 673, 860, "14:43:01.673860", "\195\216\066\144\181\222\233\064" ; 23, 25, 7, 498, 369, "23:25:07.498369", "\198\197\081\249\055\149\244\064" ; 3, 22, 26, 342, 581, "03:22:26.342581", "\158\183\177\217\043\185\199\064" ; 8, 59, 4, 343, 719, "08:59:04.343719", "\001\250\125\255\021\150\223\064" ; 2, 48, 9, 622, 724, "02:48:09.622724", "\055\135\107\181\207\180\195\064" ; 1, 13, 6, 487, 151, "01:13:06.487151", "\055\141\237\181\124\034\177\064" ; 12, 47, 5, 780, 722, "12:47:05.780722", "\040\180\172\251\056\121\230\064" ; 17, 2, 48, 208, 386, "17:02:48.208386", "\222\029\025\171\006\247\237\064" ; 2, 18, 38, 199, 949, "02:18:38.199949", "\239\199\237\151\025\063\192\064" ; 8, 6, 17, 564, 965, "08:06:17.564965", "\152\245\098\040\100\126\220\064" ; 6, 42, 24, 504, 638, "06:42:24.504638", "\149\046\253\075\032\148\215\064" ; 15, 40, 43, 570, 740, "15:40:43.570740", "\081\136\128\067\114\143\235\064" ; 8, 39, 27, 644, 248, "08:39:27.644248", "\161\246\091\059\233\111\222\064" ; 12, 13, 29, 943, 596, "12:13:29.943596", "\020\061\240\049\062\125\229\064" ; 13, 51, 57, 816, 534, "13:51:57.816534", "\066\233\011\033\186\095\232\064" ; 1, 48, 56, 453, 891, "01:48:56.453891", "\243\088\051\050\116\136\185\064" ; 6, 50, 6, 902, 89, "06:50:06.902089", "\069\128\211\187\185\007\216\064" ; 22, 23, 36, 441, 423, "22:23:36.441423", "\076\144\017\016\135\174\243\064" ; 19, 32, 3, 494, 137, "19:32:03.494137", "\236\050\252\231\055\043\241\064" ; 9, 43, 25, 855, 742, "09:43:25.855742", "\250\011\061\098\187\023\225\064" ; 14, 7, 59, 176, 639, "14:07:59.176639", "\006\213\006\167\229\215\232\064" ; 13, 13, 5, 926, 300, "13:13:05.926300", "\201\229\063\164\061\060\231\064" ; 4, 23, 13, 693, 639, "04:23:13.693639", "\029\170\041\201\216\216\206\064" ; 1, 4, 2, 641, 134, "01:04:02.641134", "\181\052\183\066\072\005\174\064" ; 1, 11, 13, 428, 370, "01:11:13.428370", "\150\004\168\169\109\177\176\064" ; 3, 12, 25, 965, 37, "03:12:25.965037", "\055\025\085\134\251\140\198\064" ; 10, 51, 48, 113, 153, "10:51:48.113153", "\078\010\243\158\131\024\227\064" ; 22, 59, 39, 571, 313, "22:59:39.571313", "\172\025\025\036\185\053\244\064" ; 22, 21, 12, 465, 542, "22:21:12.465542", "\014\043\220\114\135\165\243\064" ; 9, 56, 30, 17, 333, "09:56:30.017333", "\133\239\253\141\192\121\225\064" ; 9, 48, 47, 370, 406, "09:48:47.370406", "\008\175\093\218\235\063\225\064" ; 9, 59, 59, 353, 303, "09:59:59.353303", "\211\023\066\078\235\147\225\064" ; 2, 8, 59, 270, 792, "02:08:59.270792", "\005\224\159\082\069\059\190\064" ; 3, 27, 7, 941, 545, "03:27:07.941545", "\092\235\139\132\248\069\200\064" ; 3, 29, 7, 957, 600, "03:29:07.957600", "\083\005\163\146\250\129\200\064" ; 6, 36, 59, 970, 134, "06:36:59.970134", "\176\234\172\022\254\066\215\064" ; 22, 47, 18, 29, 361, "22:47:18.029361", "\108\061\067\120\096\007\244\064" ; 21, 6, 5, 939, 716, "21:06:05.939716", "\248\164\019\009\223\139\242\064" ; 22, 10, 37, 838, 91, "22:10:37.838091", "\193\027\210\104\221\125\243\064" ; 7, 12, 26, 73, 531, "07:12:26.073531", "\016\094\187\180\132\086\217\064" ; 13, 57, 16, 943, 423, "13:57:16.943423", "\105\110\133\048\158\135\232\064" ; 2, 25, 31, 349, 684, "02:25:31.349684", "\248\255\113\194\172\013\193\064" ; 0, 18, 16, 684, 549, "00:18:16.684549", "\010\190\105\250\188\034\145\064" ; 21, 19, 47, 90, 938, "21:19:47.090938", "\127\103\123\116\049\191\242\064" ; 13, 29, 10, 432, 665, "13:29:10.432665", "\036\069\100\216\205\180\231\064" ; 9, 43, 35, 333, 911, "09:43:35.333911", "\025\031\102\175\234\024\225\064" ; 3, 7, 2, 621, 678, "03:07:02.621678", "\082\011\037\147\079\235\197\064" ; 21, 17, 41, 729, 800, "21:17:41.729800", "\202\195\066\173\091\183\242\064" ; 19, 59, 59, 446, 178, "19:59:59.446178", "\227\138\139\035\247\147\241\064" ; 11, 30, 1, 324, 233, "11:30:01.324233", "\105\226\029\096\042\055\228\064" ; 11, 15, 0, 857, 202, "11:15:00.857202", "\131\227\050\110\155\198\227\064" ; 18, 3, 25, 193, 133, "18:03:25.193133", "\217\065\037\046\166\189\239\064" ; 6, 13, 15, 432, 704, "06:13:15.432704", "\054\030\108\177\219\222\213\064" ; 17, 8, 48, 512, 721, "17:08:48.512721", "\223\222\053\104\016\036\238\064" ; 17, 46, 1, 0, 291, "17:46:01.000291", "\111\069\098\002\032\059\239\064" ; 15, 12, 38, 913, 624, "15:12:38.913624", "\027\102\104\060\221\188\234\064" ; 15, 24, 19, 60, 382, "15:24:19.060382", "\104\059\166\238\097\020\235\064" ; 6, 8, 40, 381, 940, "06:08:40.381940", "\067\120\180\113\024\154\213\064" ; 18, 50, 3, 762, 878, "18:50:03.762878", "\206\143\191\052\188\141\240\064" ; 22, 1, 32, 794, 664, "22:01:32.794664", "\053\153\241\182\204\091\243\064" ; 15, 18, 30, 863, 858, "15:18:30.863858", "\076\136\185\164\219\232\234\064" ; 7, 3, 48, 304, 649, "07:03:48.304649", "\241\132\094\127\019\213\216\064" ; 4, 12, 59, 507, 527, "04:12:59.507527", "\107\013\165\246\192\165\205\064" ; 5, 35, 10, 200, 250, "05:35:10.200250", "\066\096\229\208\140\163\211\064" ; 7, 56, 5, 103, 149, "07:56:05.103149", "\103\067\254\153\070\229\219\064" ; 23, 20, 48, 38, 366, "23:20:48.038366", "\180\170\037\157\000\133\244\064" ; 21, 7, 13, 31, 422, "21:07:13.031422", "\230\090\180\128\016\144\242\064" ; 11, 4, 46, 584, 609, "11:04:46.584609", "\255\238\029\181\210\121\227\064" ; 6, 9, 0, 628, 570, "06:09:00.628570", "\080\170\125\058\040\159\213\064" ; 3, 30, 32, 30, 431, "03:30:32.030431", "\229\186\041\229\003\172\200\064" ; 4, 44, 52, 311, 12, "04:44:52.311012", "\043\224\158\231\019\177\208\064" ; 19, 8, 57, 834, 368, "19:08:57.834368", "\141\066\146\089\157\212\240\064" ; 4, 22, 24, 509, 400, "04:22:24.509400", "\075\234\004\052\065\192\206\064" ; 15, 33, 36, 913, 10, "15:33:36.913010", "\094\191\096\055\029\090\235\064" ; 22, 36, 34, 618, 375, "22:36:34.618375", "\027\047\221\228\041\223\243\064" ; 16, 45, 35, 841, 988, "16:45:35.841988", "\116\209\144\241\250\117\237\064" ; 14, 37, 16, 23, 957, "14:37:16.023957", "\112\120\065\196\128\179\233\064" ; 3, 31, 24, 177, 288, "03:31:24.177288", "\252\136\095\177\022\198\200\064" ; 4, 24, 26, 184, 99, "04:24:26.184099", "\029\088\142\144\023\253\206\064" ; 7, 46, 10, 411, 132, "07:46:10.411132", "\150\151\252\079\154\080\219\064" ; 22, 52, 38, 68, 217, "22:52:38.068217", "\128\181\106\023\097\027\244\064" ; 7, 59, 52, 872, 822, "07:59:52.872822", "\079\206\080\220\055\030\220\064" ; 16, 58, 12, 863, 228, "16:58:12.863228", "\159\083\144\159\155\212\237\064" ; 12, 48, 32, 393, 907, "12:48:32.393907", "\085\218\226\154\012\132\230\064" ; 4, 19, 9, 196, 537, "04:19:09.196537", "\186\217\031\040\153\094\206\064" ; 5, 39, 10, 444, 855, "05:39:10.444855", "\029\027\129\120\156\223\211\064" ; 2, 19, 4, 358, 190, "02:19:04.358190", "\225\127\043\217\045\076\192\064" ; 11, 48, 24, 336, 293, "11:48:24.336293", "\156\137\233\194\010\193\228\064" ; 9, 45, 55, 105, 143, "09:45:55.105143", "\077\218\084\093\099\042\225\064" ; 5, 27, 50, 560, 773, "05:27:50.560773", "\223\111\180\227\163\053\211\064" ; 10, 45, 24, 500, 743, "10:45:24.500743", "\022\047\022\006\144\232\226\064" ; 19, 0, 6, 745, 117, "19:00:06.745117", "\171\205\255\235\107\179\240\064" ; 6, 7, 49, 647, 893, "06:07:49.647893", "\148\051\020\119\105\141\213\064" ; 15, 8, 21, 941, 553, "15:08:21.941553", "\206\193\051\033\190\156\234\064" ; 6, 17, 2, 137, 746, "06:17:02.137746", "\074\153\212\208\136\023\214\064" ; 8, 4, 34, 866, 618, "08:04:34.866618", "\008\088\171\118\183\100\220\064" ; 20, 7, 27, 317, 869, "20:07:27.317869", "\246\205\253\021\245\175\241\064" ; 16, 21, 29, 473, 328, "16:21:29.473328", "\009\195\128\037\047\193\236\064" ; 11, 32, 20, 383, 224, "11:32:20.383224", "\098\250\094\067\140\072\228\064" ; 21, 17, 37, 179, 241, "21:17:37.179241", "\146\207\043\222\018\183\242\064" ; 11, 45, 22, 777, 710, "11:45:22.777710", "\249\020\000\227\088\170\228\064" ; 9, 13, 1, 285, 486, "09:13:01.285486", "\047\137\179\034\169\051\224\064" ; 15, 4, 56, 63, 527, "15:04:56.063527", "\109\198\105\008\002\131\234\064" ; 0, 34, 51, 425, 347, "00:34:51.425347", "\232\252\020\199\217\086\160\064" ; 18, 57, 15, 987, 140, "18:57:15.987140", "\009\080\083\203\191\168\240\064" ; 9, 47, 7, 878, 696, "09:47:07.878696", "\228\018\071\030\124\051\225\064" ; 6, 11, 57, 677, 118, "06:11:57.677118", "\098\188\230\085\107\203\213\064" ; 16, 31, 31, 272, 484, "16:31:31.272484", "\149\093\048\184\104\012\237\064" ; 7, 10, 2, 41, 226, "07:10:02.041226", "\112\096\114\163\130\050\217\064" ; 11, 2, 40, 875, 282, "11:02:40.875282", "\153\101\079\002\028\106\227\064" ; 20, 47, 39, 959, 581, "20:47:39.959581", "\078\155\113\090\191\070\242\064" ; 1, 37, 35, 850, 45, "01:37:35.850045", "\033\147\140\156\217\223\182\064" ; 23, 8, 35, 357, 425, "23:08:35.357425", "\221\070\003\184\053\087\244\064" ; 6, 56, 21, 145, 790, "06:56:21.145790", "\133\148\159\084\073\101\216\064" ; 6, 3, 14, 112, 492, "06:03:14.112492", "\068\165\017\051\135\072\213\064" ; 2, 50, 58, 769, 681, "02:50:58.769681", "\173\049\232\132\098\009\196\064" ; 16, 9, 44, 198, 982, "16:09:44.198982", "\207\127\015\094\006\105\236\064" ; 0, 17, 31, 82, 944, "00:17:31.082944", "\153\157\069\239\084\108\144\064" ; 11, 40, 19, 997, 765, "11:40:19.997765", "\131\221\176\237\127\132\228\064" ; 17, 14, 8, 406, 575, "17:14:08.406575", "\012\147\169\002\013\076\238\064" ; 20, 55, 46, 682, 618, "20:55:46.682618", "\027\218\000\236\042\101\242\064" ; 2, 35, 16, 488, 95, "02:35:16.488095", "\043\159\229\121\062\050\194\064" ; 10, 46, 50, 837, 463, "10:46:50.837463", "\147\052\127\204\090\243\226\064" ; 22, 43, 53, 328, 868, "22:43:53.328868", "\139\023\011\067\149\250\243\064" ; 17, 45, 50, 536, 200, "17:45:50.536200", "\004\231\140\040\209\057\239\064" ; 9, 31, 15, 153, 663, "09:31:15.153663", "\243\170\206\234\100\188\224\064" ; 2, 40, 1, 897, 918, "02:40:01.897918", "\063\030\250\238\242\192\194\064" ; 19, 12, 20, 309, 689, "19:12:20.309689", "\238\115\124\244\068\225\240\064" ; 8, 23, 14, 803, 971, "08:23:14.803971", "\252\199\066\116\179\124\221\064" ; 8, 14, 33, 841, 0, "08:14:33.841000", "\252\169\241\210\117\250\220\064" ; 8, 3, 23, 318, 303, "08:03:23.318303", "\206\139\019\095\212\082\220\064" ; 17, 21, 8, 459, 286, "17:21:08.459286", "\177\141\120\178\142\128\238\064" ; 14, 34, 37, 936, 873, "14:34:37.936873", "\240\021\221\250\189\159\233\064" ; 11, 55, 26, 600, 926, "11:55:26.600926", "\170\041\201\058\211\245\228\064" ; 15, 57, 24, 766, 755, "15:57:24.766755", "\034\200\065\137\152\012\236\064" ; 7, 55, 36, 62, 944, "07:55:36.062944", "\095\069\070\007\004\222\219\064" ; 16, 54, 13, 58, 365, "16:54:13.058365", "\199\070\032\222\161\182\237\064" ; 1, 32, 20, 731, 440, "01:32:20.731440", "\252\222\166\063\187\164\181\064" ; 22, 14, 35, 809, 770, "22:14:35.809770", "\052\099\209\244\188\140\243\064" ; 1, 13, 5, 61, 188, "01:13:05.061188", "\232\074\004\170\015\033\177\064" ; 12, 28, 0, 827, 460, "12:28:00.827460", "\216\100\141\122\026\234\229\064" ; 9, 41, 28, 10, 675, "09:41:28.010675", "\253\024\115\087\000\009\225\064" ; 16, 15, 44, 346, 438, "16:15:44.346438", "\003\037\005\022\011\150\236\064" ; 7, 7, 57, 577, 530, "07:07:57.577530", "\158\099\064\246\100\019\217\064" ; 4, 39, 40, 295, 330, "04:39:40.295330", "\225\204\175\230\018\099\208\064" ; 2, 49, 24, 293, 880, "02:49:24.293880", "\121\030\220\157\037\218\195\064" ; 13, 19, 18, 515, 307, "13:19:18.515307", "\013\027\101\125\208\106\231\064" ; 23, 41, 15, 755, 512, "23:41:15.755512", "\060\192\147\022\188\209\244\064" ; 12, 14, 35, 112, 757, "12:14:35.112757", "\109\145\180\155\099\133\229\064" ; 3, 55, 3, 146, 787, "03:55:03.146787", "\062\154\234\201\146\139\203\064" ; 4, 45, 5, 630, 84, "04:45:05.630084", "\111\215\075\083\104\180\208\064" ; 3, 44, 26, 86, 193, "03:44:26.086193", "\018\074\095\008\011\077\202\064" ; 15, 16, 34, 607, 708, "15:16:34.607708", "\049\012\088\114\083\218\234\064" ; 14, 12, 31, 467, 552, "14:12:31.467552", "\165\156\047\246\238\249\232\064" ; 2, 32, 30, 879, 834, "02:32:30.879834", "\245\135\102\158\112\223\193\064" ; 15, 41, 11, 872, 267, "15:41:11.872267", "\205\123\156\233\251\146\235\064" ; 16, 30, 35, 527, 480, "16:30:35.527480", "\170\188\029\225\112\005\237\064" ; 10, 19, 55, 989, 814, "10:19:55.989814", "\228\104\142\172\127\041\226\064" ; 17, 34, 56, 728, 942, "17:34:56.728942", "\086\044\126\083\023\232\238\064" ; 2, 24, 28, 931, 14, "02:24:28.931014", "\015\125\119\043\119\238\192\064" ; 5, 4, 10, 107, 435, "05:04:10.107435", "\221\012\055\224\134\210\209\064" ; 1, 33, 49, 661, 946, "01:33:49.661946", "\184\005\075\117\169\253\181\064" ; 18, 41, 27, 270, 534, "18:41:27.270534", "\168\117\027\084\116\109\240\064" ; 7, 49, 34, 100, 1, "07:49:34.100001", "\036\152\106\102\134\131\219\064" ; 8, 19, 8, 128, 77, "08:19:08.128077", "\152\223\105\050\008\063\221\064" ; 16, 21, 14, 539, 425, "16:21:14.539425", "\180\055\248\066\081\191\236\064" ; 14, 21, 44, 423, 146, "14:21:44.423146", "\238\122\105\138\013\063\233\064" ; 21, 33, 52, 727, 791, "21:33:52.727791", "\245\044\008\165\011\244\242\064" ; 13, 14, 26, 703, 904, "13:14:26.703904", "\113\174\097\134\086\070\231\064" ; 3, 54, 46, 431, 86, "03:54:46.431086", "\226\119\211\045\055\131\203\064" ; 21, 49, 45, 796, 512, "21:49:45.796512", "\238\093\131\190\156\047\243\064" ; 17, 56, 10, 527, 714, "17:56:10.527714", "\117\120\008\227\080\135\239\064" ; 9, 33, 45, 8, 425, "09:33:45.008425", "\111\129\004\069\032\207\224\064" ; 23, 41, 45, 264, 306, "23:41:45.264306", "\162\237\152\058\148\211\244\064" ; 12, 38, 59, 319, 500, "12:38:59.319500", "\099\016\088\057\106\060\230\064" ; 17, 16, 15, 613, 574, "17:16:15.613574", "\245\240\101\162\243\091\238\064" ; 4, 22, 51, 449, 669, "04:22:51.449669", "\131\248\192\142\185\205\206\064" ; 4, 8, 31, 93, 875, "04:08:31.093875", "\117\147\024\004\140\031\205\064" ; 18, 37, 43, 245, 402, "18:37:43.245402", "\198\165\042\237\115\095\240\064" ; 20, 47, 24, 779, 664, "20:47:24.779664", "\094\245\128\121\204\069\242\064" ; 11, 22, 0, 217, 964, "11:22:00.217964", "\118\163\143\249\006\251\227\064" ; 16, 11, 6, 503, 268, "16:11:06.503268", "\036\126\197\026\080\115\236\064" ; 16, 35, 12, 357, 555, "16:35:12.357555", "\241\046\023\113\011\040\237\064" ; 9, 28, 20, 842, 425, "09:28:20.842425", "\010\070\037\245\154\166\224\064" ; 22, 18, 29, 272, 925, "22:18:29.272925", "\212\154\230\093\084\155\243\064" ; 6, 19, 41, 83, 567, "06:19:41.083567", "\001\103\041\089\069\063\214\064" ; 21, 17, 14, 63, 170, "21:17:14.063170", "\193\139\190\002\161\181\242\064" ; 10, 34, 17, 912, 485, "10:34:17.912485", "\034\190\019\051\061\149\226\064" ; 12, 49, 2, 798, 750, "12:49:02.798750", "\246\040\092\143\217\135\230\064" ; 23, 57, 34, 926, 620, "23:57:34.926620", "\062\126\111\211\238\014\245\064" ; 1, 51, 16, 611, 851, "01:51:16.611851", "\006\099\068\162\156\020\186\064" ; 11, 6, 30, 961, 691, "11:06:30.961691", "\060\052\044\198\222\134\227\064" ; 4, 13, 51, 856, 372, "04:13:51.856372", "\155\002\153\157\237\191\205\064" ; 10, 55, 12, 846, 920, "10:55:12.846920", "\202\248\247\025\027\050\227\064" ; 3, 38, 27, 337, 268, "03:38:27.337268", "\254\010\153\043\171\153\201\064" ; 20, 26, 42, 220, 0, "20:26:42.220000", "\082\184\030\133\035\248\241\064" ; 23, 34, 33, 954, 199, "23:34:33.954199", "\174\043\102\068\159\184\244\064" ; 16, 7, 54, 788, 687, "16:07:54.788687", "\249\132\236\060\089\091\236\064" ; 11, 9, 31, 351, 664, "11:09:31.351664", "\102\220\212\064\107\157\227\064" ; 21, 38, 49, 272, 385, "21:38:49.272385", "\175\095\176\091\148\006\243\064" ; 14, 49, 29, 456, 640, "14:49:29.456640", "\065\125\203\156\046\015\234\064" ; 5, 26, 5, 633, 510, "05:26:05.633510", "\237\134\109\139\104\027\211\064" ; 2, 16, 28, 309, 761, "02:16:28.309761", "\148\052\127\076\079\252\191\064" ; 18, 24, 9, 935, 75, "18:24:09.935075", "\005\052\017\246\158\044\240\064" ; 3, 22, 12, 670, 297, "03:22:12.670297", "\206\198\074\204\085\178\199\064" ; 12, 17, 29, 982, 425, "12:17:29.982425", "\185\141\006\112\063\155\229\064" ; 20, 6, 49, 836, 3, "20:06:49.836003", "\133\174\068\096\157\173\241\064" ; 3, 32, 13, 65, 147, "03:32:13.065147", "\056\165\188\086\136\222\200\064" ; 6, 43, 58, 255, 188, "06:43:58.255188", "\150\012\000\085\144\171\215\064" ; 19, 8, 54, 357, 792, "19:08:54.357792", "\173\026\132\185\101\212\240\064" ; 0, 39, 10, 869, 540, "00:39:10.869540", "\033\205\088\052\189\093\162\064" ; 9, 23, 41, 150, 576, "09:23:41.150576", "\114\194\132\209\164\131\224\064" ; 12, 40, 33, 319, 186, "12:40:33.319186", "\235\142\197\054\042\072\230\064" ; 4, 21, 7, 490, 194, "04:21:07.490194", "\089\079\173\190\190\153\206\064" ; 2, 44, 8, 749, 967, "02:44:08.749967", "\010\045\235\254\095\060\195\064" ; 14, 24, 32, 132, 262, "14:24:32.132262", "\144\132\125\059\004\084\233\064" ; 4, 39, 34, 667, 434, "04:39:34.667434", "\144\024\061\183\170\097\208\064" ; 6, 1, 14, 449, 386, "06:01:14.449386", "\082\127\189\194\156\042\213\064" ; 19, 24, 9, 218, 957, "19:24:09.218957", "\035\014\217\128\147\013\241\064" ; 0, 28, 52, 653, 781, "00:28:52.653781", "\252\054\196\120\157\018\155\064" ; 16, 38, 22, 612, 674, "16:38:22.612674", "\036\129\006\155\211\063\237\064" ; 20, 17, 57, 216, 764, "20:17:57.216764", "\047\135\221\119\083\215\241\064" ; 13, 51, 25, 617, 331, "13:51:25.617331", "\250\240\044\193\179\091\232\064" ; 9, 45, 21, 837, 199, "09:45:21.837199", "\168\142\085\202\058\038\225\064" ; 2, 54, 38, 203, 923, "02:54:38.203923", "\243\027\038\026\026\119\196\064" ; 12, 53, 13, 744, 929, "12:53:13.744929", "\155\087\117\214\055\167\230\064" ; 3, 29, 41, 942, 323, "03:29:41.942323", "\162\065\010\158\248\146\200\064" ; 9, 31, 53, 658, 994, "09:31:53.658994", "\201\149\122\022\053\193\224\064" ; 4, 22, 44, 794, 808, "04:22:44.794808", "\077\191\068\188\101\202\206\064" ; 22, 24, 15, 207, 914, "22:24:15.207914", "\102\161\157\083\243\176\243\064" ; 19, 22, 42, 674, 308, "19:22:42.674308", "\119\047\247\201\042\008\241\064" ; 0, 20, 56, 473, 645, "00:20:56.473645", "\168\227\049\003\229\161\147\064" ; 22, 41, 54, 224, 696, "22:41:54.224696", "\057\213\090\152\035\243\243\064" ; 14, 45, 24, 305, 712, "14:45:24.305712", "\064\136\100\200\137\240\233\064" ; 23, 26, 40, 420, 168, "23:26:40.420168", "\173\020\002\185\006\155\244\064" ; 19, 56, 0, 133, 811, "19:56:00.133811", "\206\000\023\036\002\133\241\064" ; 12, 27, 10, 959, 624, "12:27:10.959624", "\015\100\061\181\222\227\229\064" ; 4, 7, 27, 587, 131, "04:07:27.587131", "\188\205\027\039\203\255\204\064" ; 3, 1, 47, 218, 345, "03:01:47.218345", "\032\157\186\242\155\077\197\064" ; 1, 35, 2, 206, 361, "01:35:02.206361", "\044\018\019\212\052\070\182\064" ; 20, 50, 29, 131, 1, "20:50:29.131001", "\043\129\148\024\082\081\242\064" ; 4, 20, 5, 460, 975, "04:20:05.460975", "\163\146\058\001\187\122\206\064" ; 6, 21, 1, 604, 41, "06:21:01.604041", "\028\149\155\168\102\083\214\064" ; 19, 56, 28, 777, 94, "19:56:28.777094", "\063\030\250\110\204\134\241\064" ; 4, 49, 25, 53, 224, "04:49:25.053224", "\215\162\005\104\067\245\208\064" ; 21, 58, 11, 9, 147, "21:58:11.009147", "\030\083\119\037\048\079\243\064" ; 2, 1, 35, 670, 504, "02:01:35.670504", "\214\111\038\166\171\127\188\064" ; 12, 40, 33, 977, 786, "12:40:33.977786", "\143\221\005\074\063\072\230\064" ; 21, 23, 24, 577, 115, "21:23:24.577115", "\049\240\220\059\201\204\242\064" ; 5, 28, 44, 294, 690, "05:28:44.294690", "\030\114\051\220\018\067\211\064" ; 23, 33, 54, 204, 967, "23:33:54.204967", "\028\122\139\071\035\182\244\064" ; 14, 25, 13, 568, 765, "14:25:13.568765", "\067\168\082\051\050\089\233\064" ; 7, 55, 21, 956, 58, "07:55:21.956058", "\197\228\013\048\125\218\219\064" ; 6, 28, 20, 354, 916, "06:28:20.354916", "\053\153\241\182\022\193\214\064" ; 11, 5, 57, 930, 484, "11:05:57.930484", "\174\097\134\198\189\130\227\064" ; 19, 41, 44, 427, 252, "19:41:44.427252", "\114\049\006\214\134\079\241\064" ; 0, 2, 30, 284, 306, "00:02:30.284306", "\207\129\229\008\025\201\098\064" ; 6, 4, 34, 737, 697, "06:04:34.737697", "\087\122\109\054\175\092\213\064" ; 1, 12, 42, 89, 652, "01:12:42.089652", "\005\248\110\243\022\010\177\064" ; 0, 21, 5, 500, 116, "00:21:05.500116", "\211\160\104\030\000\198\147\064" ; 9, 35, 57, 994, 69, "09:35:57.994069", "\159\202\105\207\191\223\224\064" ; 2, 39, 48, 156, 39, "02:39:48.156039", "\244\000\022\249\019\186\194\064" ; 9, 7, 45, 42, 229, "09:07:45.042229", "\190\161\240\089\033\012\224\064" ; 4, 2, 0, 832, 504, "04:02:00.832504", "\229\182\125\143\106\092\204\064" ; 6, 0, 40, 643, 814, "06:00:40.643814", "\173\162\063\052\041\034\213\064" ; 9, 39, 8, 310, 681, "09:39:08.310681", "\207\071\025\241\137\247\224\064" ; 0, 42, 50, 663, 321, "00:42:50.663321", "\128\099\207\158\083\021\164\064" ; 20, 25, 7, 337, 943, "20:25:07.337943", "\079\235\054\104\053\242\241\064" ; 18, 57, 42, 586, 346, "18:57:42.586346", "\226\087\172\097\105\170\240\064" ; 1, 21, 32, 207, 149, "01:21:32.207149", "\103\132\183\007\053\028\179\064" ; 23, 41, 47, 541, 124, "23:41:47.541124", "\177\163\113\168\184\211\244\064" ; 16, 47, 44, 908, 931, "16:47:44.908931", "\235\118\246\021\029\134\237\064" ; 14, 28, 17, 88, 151, "14:28:17.088151", "\196\011\034\210\034\112\233\064" ; 14, 44, 15, 781, 226, "14:44:15.781226", "\025\171\205\255\248\231\233\064" ; 19, 8, 20, 185, 871, "19:08:20.185871", "\164\222\083\249\066\210\240\064" ; 11, 54, 30, 534, 559, "11:54:30.534559", "\217\121\027\027\209\238\228\064" ; 22, 41, 33, 514, 631, "22:41:33.514631", "\040\183\237\059\216\241\243\064" ; 19, 19, 4, 171, 644, "19:19:04.171644", "\105\199\013\191\130\250\240\064" ; 20, 10, 46, 153, 758, "20:10:46.153758", "\216\242\202\117\098\188\241\064" ; 16, 43, 36, 549, 471, "16:43:36.549471", "\227\052\068\149\017\103\237\064" ; 23, 23, 50, 265, 372, "23:23:50.265372", "\212\181\246\062\100\144\244\064" ; 20, 14, 54, 931, 641, "20:14:54.931641", "\170\100\000\232\238\203\241\064" ; 20, 45, 39, 20, 558, "20:45:39.020558", "\027\160\052\084\048\063\242\064" ; 3, 2, 45, 677, 828, "03:02:45.677828", "\040\098\017\195\214\106\197\064" ; 7, 50, 28, 909, 947, "07:50:28.909947", "\134\087\146\060\058\145\219\064" ; 2, 41, 5, 381, 406, "02:41:05.381406", "\063\108\233\209\176\224\194\064" ; 3, 35, 30, 347, 90, "03:35:30.347090", "\098\243\113\109\044\065\201\064" ; 14, 5, 49, 14, 90, "14:05:49.014090", "\039\223\108\115\160\199\232\064" ; 15, 8, 21, 603, 100, "15:08:21.603100", "\007\095\152\076\179\156\234\064" ; 4, 49, 59, 974, 507, "04:49:59.974507", "\174\155\082\094\254\253\208\064" ; 19, 31, 11, 858, 283, "19:31:11.858283", "\123\244\134\187\253\039\241\064" ; 19, 10, 14, 982, 749, "19:10:14.982749", "\243\003\087\185\111\217\240\064" ; 13, 33, 37, 730, 108, "13:33:37.730108", "\210\115\011\093\055\214\231\064" ; 7, 39, 46, 351, 239, "07:39:46.351239", "\133\036\179\122\150\240\218\064" ; 2, 34, 25, 166, 392, "02:34:25.166392", "\040\067\085\076\149\024\194\064" ; 7, 34, 27, 526, 559, "07:34:27.526559", "\027\133\036\179\225\160\218\064" ; 18, 15, 12, 766, 202, "18:15:12.766202", "\066\007\093\066\012\011\240\064" ; 12, 22, 1, 105, 176, "12:22:01.105176", "\011\015\154\093\035\189\229\064" ; 23, 57, 35, 960, 172, "23:57:35.960172", "\169\080\221\092\255\014\245\064" ; 22, 15, 52, 537, 174, "22:15:52.537174", "\164\195\067\152\136\145\243\064" ; 7, 4, 17, 577, 6, "07:04:17.577006", "\230\146\170\237\100\220\216\064" ; 23, 39, 56, 301, 244, "23:39:56.301244", "\130\058\229\209\196\204\244\064" ; 22, 0, 1, 286, 397, "22:00:01.286397", "\074\005\021\149\020\086\243\064" ; 11, 38, 58, 399, 663, "11:38:58.399663", "\077\015\010\202\076\122\228\064" ; 1, 54, 10, 917, 388, "01:54:10.917388", "\191\161\240\217\234\194\186\064" ; 23, 42, 56, 34, 841, "23:42:56.034841", "\185\111\181\142\000\216\244\064" ; 7, 13, 11, 94, 453, "07:13:11.094453", "\129\152\132\011\198\097\217\064" ; 0, 34, 13, 717, 333, "00:34:13.717333", "\175\094\069\070\111\011\160\064" ; 8, 44, 5, 525, 720, "08:44:05.525720", "\183\127\101\165\097\181\222\064" ; 10, 25, 44, 594, 684, "10:25:44.594684", "\110\189\166\007\019\085\226\064" ; 14, 22, 54, 728, 153, "14:22:54.728153", "\048\133\007\077\215\071\233\064" ; 0, 16, 23, 488, 91, "00:16:23.488091", "\199\019\065\156\231\187\142\064" ; 2, 28, 2, 82, 378, "02:28:02.082378", "\245\191\092\139\010\089\193\064" ; 8, 7, 50, 694, 854, "08:07:50.694854", "\096\233\124\120\172\149\220\064" ; 7, 17, 32, 479, 891, "07:17:32.479891", "\169\189\136\182\030\163\217\064" ; 17, 55, 24, 244, 982, "17:55:24.244982", "\195\125\228\214\135\129\239\064" ; 13, 41, 1, 121, 455, "13:41:01.121455", "\158\152\245\226\163\013\232\064" ; 19, 10, 56, 6, 825, "19:10:56.006825", "\252\135\244\027\000\220\240\064" ; 12, 18, 47, 622, 947, "12:18:47.622947", "\005\140\046\239\243\164\229\064" ; 10, 40, 7, 453, 671, "10:40:07.453671", "\133\011\121\132\238\192\226\064" ; 2, 17, 16, 545, 826, "02:17:16.545826", "\167\089\160\221\069\022\192\064" ; 12, 48, 29, 371, 235, "12:48:29.371235", "\004\057\040\225\171\131\230\064" ; 0, 55, 20, 659, 569, "00:55:20.659569", "\233\040\007\179\081\241\169\064" ; 13, 12, 56, 158, 284, "13:12:56.158284", "\112\155\169\016\005\059\231\064" ; 23, 1, 54, 687, 490, "23:01:54.687490", "\166\131\245\255\042\062\244\064" ; 7, 11, 49, 432, 696, "07:11:49.432696", "\071\144\074\177\091\077\217\064" ; 10, 42, 36, 568, 30, "10:42:36.568030", "\037\064\077\045\146\211\226\064" ; 17, 59, 45, 859, 743, "17:59:45.859743", "\126\192\003\131\059\162\239\064" ; 22, 34, 8, 977, 137, "22:34:08.977137", "\043\104\090\162\015\214\243\064" ; 4, 36, 23, 959, 364, "04:36:23.959364", "\061\067\056\102\253\049\208\064" ; 4, 2, 40, 21, 969, "04:02:40.021969", "\068\084\225\207\002\112\204\064" ; 0, 42, 18, 582, 752, "00:42:18.582752", "\091\091\120\094\042\213\163\064" ; 20, 26, 11, 219, 731, "20:26:11.219731", "\046\167\004\132\051\246\241\064" ; 2, 36, 45, 236, 407, "02:36:45.236407", "\198\166\149\066\158\094\194\064" ; 5, 16, 29, 254, 264, "05:16:29.254264", "\035\131\220\069\080\139\210\064" ; 9, 7, 46, 834, 547, "09:07:46.834547", "\000\233\155\180\090\012\224\064" ; 15, 12, 36, 275, 951, "15:12:36.275951", "\010\049\151\212\136\188\234\064" ; 8, 23, 8, 334, 955, "08:23:08.334955", "\168\024\231\111\021\123\221\064" ; 4, 51, 11, 151, 875, "04:51:11.151875", "\134\235\081\184\201\015\209\064" ; 20, 9, 20, 438, 958, "20:09:20.438958", "\229\210\248\005\007\183\241\064" ; 2, 35, 46, 541, 344, "02:35:46.541344", "\241\155\194\074\069\065\194\064" ; 2, 58, 50, 333, 37, "02:58:50.333037", "\174\215\244\160\042\245\196\064" ; 1, 49, 43, 927, 320, "01:49:43.927320", "\237\240\215\100\237\183\185\064" ; 19, 5, 36, 63, 985, "19:05:36.063985", "\167\034\021\006\001\200\240\064" ; 9, 12, 27, 666, 199, "09:12:27.666199", "\180\144\128\081\117\047\224\064" ; 15, 44, 5, 607, 150, "15:44:05.607150", "\057\214\197\109\179\168\235\064" ; 15, 33, 20, 799, 393, "15:33:20.799393", "\245\160\160\148\025\088\235\064" ; 9, 45, 44, 507, 15, "09:45:44.507015", "\114\133\119\057\016\041\225\064" ; 11, 31, 58, 381, 85, "11:31:58.381085", "\128\043\217\049\204\069\228\064" ; 2, 35, 49, 23, 594, "02:35:49.023594", "\048\209\032\005\131\066\194\064" ; 23, 33, 11, 411, 523, "23:33:11.411523", "\040\036\153\149\118\179\244\064" ; 11, 35, 18, 213, 840, "11:35:18.213840", "\211\251\198\215\198\094\228\064" ; 12, 32, 40, 300, 60, "12:32:40.300060", "\219\109\023\154\009\013\230\064" ; 18, 59, 30, 180, 852, "18:59:30.180852", "\022\017\197\228\034\177\240\064" ; 4, 59, 36, 660, 193, "04:59:36.660193", "\003\036\154\064\042\142\209\064" ; 12, 36, 44, 161, 886, "12:36:44.161886", "\118\140\043\046\133\043\230\064" ; 8, 50, 30, 312, 695, "08:50:30.312695", "\168\227\049\003\148\021\223\064" ; 2, 39, 17, 978, 487, "02:39:17.978487", "\071\224\015\063\253\170\194\064" ; 2, 13, 43, 126, 615, "02:13:43.126615", "\047\052\215\105\032\087\191\064" ; 20, 43, 41, 250, 653, "20:43:41.250653", "\090\184\172\002\212\055\242\064" ; 15, 14, 55, 858, 584, "15:14:55.858584", "\028\039\133\121\251\205\234\064" ; 14, 39, 15, 401, 770, "14:39:15.401770", "\080\194\076\219\108\194\233\064" ; 6, 4, 10, 187, 424, "06:04:10.187424", "\160\059\193\254\139\086\213\064" ; 17, 27, 19, 86, 334, "17:27:19.086334", "\081\133\063\195\226\174\238\064" ; 18, 42, 31, 970, 791, "18:42:31.970791", "\196\036\092\136\127\113\240\064" ; 19, 38, 43, 387, 181, "19:38:43.387181", "\074\180\228\049\054\068\241\064" ; 17, 5, 55, 944, 102, "17:05:55.944102", "\195\101\021\054\126\014\238\064" ; 6, 25, 27, 624, 995, "06:25:27.624995", "\074\007\235\255\231\149\214\064" ; 11, 32, 34, 555, 941, "11:32:34.555941", "\176\199\068\202\081\074\228\064" ; 10, 37, 10, 128, 14, "10:37:10.128014", "\237\208\176\024\196\170\226\064" ; 17, 10, 42, 900, 807, "17:10:42.900807", "\160\051\105\211\092\050\238\064" ; 9, 43, 6, 873, 400, "09:43:06.873400", "\138\142\228\242\091\021\225\064" ; 20, 59, 50, 773, 108, "20:59:50.773108", "\132\126\166\094\108\116\242\064" ; 14, 48, 54, 501, 59, "14:48:54.501059", "\075\226\172\008\208\010\234\064" ; 1, 7, 58, 831, 42, "01:07:58.831042", "\053\071\086\126\169\221\175\064" ; 5, 14, 31, 703, 31, "05:14:31.703031", "\069\188\117\254\236\109\210\064" ; 15, 53, 17, 832, 347, "15:53:17.832347", "\254\044\150\162\186\237\235\064" ; 2, 6, 33, 890, 412, "02:06:33.890412", "\248\115\010\242\227\169\189\064" ; 10, 28, 40, 235, 330, "10:28:40.235330", "\185\199\210\135\007\107\226\064" ; 0, 53, 52, 649, 459, "00:53:52.649459", "\047\218\227\133\076\065\169\064" ; 23, 14, 10, 891, 39, "23:14:10.891039", "\072\028\178\065\046\108\244\064" ; 0, 40, 24, 928, 201, "00:40:24.928201", "\058\086\041\061\219\241\162\064" ; 9, 4, 18, 408, 18, "09:04:18.408018", "\139\135\247\028\154\228\223\064" ; 14, 50, 29, 744, 498, "14:50:29.744498", "\062\120\237\210\183\022\234\064" ; 3, 3, 50, 941, 66, "03:03:50.941066", "\177\198\217\116\120\139\197\064" ; 23, 12, 12, 567, 95, "23:12:12.567095", "\235\052\210\018\201\100\244\064" ; 7, 39, 58, 989, 412, "07:39:58.989412", "\146\181\134\082\191\243\218\064" ; 19, 7, 53, 570, 533, "19:07:53.570533", "\005\054\231\032\153\208\240\064" ; 19, 12, 8, 280, 95, "19:12:08.280095", "\012\229\068\123\132\224\240\064" ; 11, 9, 47, 583, 407, "11:09:47.583407", "\040\040\069\171\114\159\227\064" ; 9, 24, 59, 170, 771, "09:24:59.170771", "\131\190\244\118\101\141\224\064" ; 20, 32, 4, 311, 911, "20:32:04.311911", "\132\099\150\253\068\012\242\064" ; 11, 59, 7, 458, 292, "11:59:07.458292", "\000\252\083\170\110\017\229\064" ; 14, 17, 41, 653, 513, "14:17:41.653513", "\080\024\148\233\180\032\233\064" ; 20, 32, 39, 868, 109, "20:32:39.868109", "\070\067\198\227\125\014\242\064" ; 4, 47, 21, 10, 866, "04:47:21.010866", "\168\078\007\178\064\214\208\064" ; 22, 40, 2, 51, 677, "22:40:02.051677", "\016\067\171\211\032\236\243\064" ; 23, 30, 11, 894, 334, "23:30:11.894334", "\027\043\049\079\062\168\244\064" ; 10, 29, 44, 494, 403, "10:29:44.494403", "\129\061\038\210\015\115\226\064" ; 17, 50, 13, 791, 932, "17:50:13.791932", "\021\199\129\087\185\090\239\064" ; 2, 41, 52, 576, 648, "02:41:52.576648", "\166\006\154\207\073\248\194\064" ; 20, 57, 4, 252, 869, "20:57:04.252869", "\082\093\192\011\004\106\242\064" ; 10, 39, 7, 702, 743, "10:39:07.702743", "\079\227\222\124\118\185\226\064" ; 10, 52, 21, 986, 546, "10:52:21.986546", "\192\234\200\145\191\028\227\064" ; 21, 45, 7, 145, 45, "21:45:07.145045", "\183\180\026\082\050\030\243\064" ; 14, 52, 48, 50, 179, "14:52:48.050179", "\127\253\016\155\001\040\234\064" ; 14, 46, 48, 807, 321, "14:46:48.807321", "\140\217\146\213\025\251\233\064" ; 2, 35, 16, 242, 106, "02:35:16.242106", "\021\084\084\253\030\050\194\064" ; 19, 52, 39, 140, 598, "19:52:39.140598", "\062\176\227\063\114\120\241\064" ; 20, 3, 6, 376, 606, "20:03:06.376606", "\088\003\148\006\166\159\241\064" ; 7, 21, 22, 460, 561, "07:21:22.460561", "\052\216\212\121\157\220\217\064" ; 14, 43, 27, 749, 525, "14:43:27.749525", "\082\218\027\252\247\225\233\064" ; 18, 11, 42, 116, 436, "18:11:42.116436", "\131\253\215\185\195\251\239\064" ; 19, 54, 55, 705, 0, "19:54:55.705000", "\123\020\174\071\251\128\241\064" ; 7, 29, 2, 171, 329, "07:29:02.171329", "\246\232\013\247\138\079\218\064" ; 5, 26, 21, 444, 401, "05:26:21.444401", "\084\228\016\113\092\031\211\064" ; 6, 56, 32, 797, 372, "06:56:32.797372", "\175\145\036\008\051\104\216\064" ; 12, 45, 56, 644, 599, "12:45:56.644599", "\001\021\142\160\148\112\230\064" ; 14, 53, 8, 730, 243, "14:53:08.730243", "\101\145\038\094\151\042\234\064" ; 9, 7, 41, 752, 115, "09:07:41.752115", "\251\121\083\017\184\011\224\064" ; 21, 8, 13, 555, 87, "21:08:13.555087", "\246\231\162\225\216\147\242\064" ; 9, 12, 32, 776, 825, "09:12:32.776825", "\055\026\192\219\024\048\224\064" ; 1, 8, 10, 189, 974, "01:08:10.189974", "\046\170\069\068\097\244\175\064" ; 17, 37, 27, 703, 122, "17:37:27.703122", "\099\181\249\127\246\250\238\064" ; 23, 27, 41, 742, 766, "23:27:41.742766", "\233\153\094\226\219\158\244\064" ; 17, 46, 29, 583, 598, "17:46:29.583598", "\128\182\213\172\178\062\239\064" ; 4, 20, 25, 605, 244, "04:20:25.605244", "\013\169\162\120\205\132\206\064" ; 10, 34, 0, 281, 400, "10:34:00.281400", "\163\146\058\001\009\147\226\064" ; 19, 4, 0, 342, 895, "19:04:00.342895", "\176\119\127\124\005\194\240\064" ; 18, 52, 45, 333, 857, "18:52:45.333857", "\009\112\122\087\213\151\240\064" ; 12, 36, 5, 809, 870, "12:36:05.809870", "\129\125\116\234\185\038\230\064" ; 16, 6, 34, 149, 926, "16:06:34.149926", "\090\156\049\204\068\081\236\064" ; 11, 1, 11, 132, 940, "11:01:11.132940", "\010\099\011\065\228\094\227\064" ; 18, 48, 15, 174, 696, "18:48:15.174696", "\108\008\142\203\242\134\240\064" ; 7, 51, 47, 188, 954, "07:51:47.188954", "\156\132\210\023\204\164\219\064" ; 21, 25, 37, 36, 59, "21:25:37.036059", "\027\154\178\147\016\213\242\064" ; 5, 52, 1, 115, 406, "05:52:01.115406", "\241\216\207\098\071\160\212\064" ; 0, 53, 28, 372, 339, "00:53:28.372339", "\013\168\055\163\190\016\169\064" ; 14, 8, 39, 572, 671, "14:08:39.572671", "\012\034\082\083\242\220\232\064" ; 16, 25, 23, 944, 281, "16:25:23.944281", "\168\201\140\055\126\222\236\064" ; 8, 49, 1, 142, 203, "08:49:01.142203", "\153\156\218\025\073\255\222\064" ; 5, 9, 48, 62, 528, "05:09:48.062528", "\198\112\117\000\004\039\210\064" ; 15, 38, 6, 459, 869, "15:38:06.459869", "\111\049\063\183\206\123\235\064" ; 10, 5, 34, 576, 486, "10:05:34.576486", "\147\196\146\114\210\189\225\064" ; 11, 13, 29, 651, 647, "11:13:29.651647", "\049\207\074\218\052\187\227\064" ; 12, 53, 45, 279, 302, "12:53:45.279302", "\119\191\010\240\040\171\230\064" ; 11, 9, 37, 976, 83, "11:09:37.976083", "\102\106\018\060\063\158\227\064" ; 16, 45, 45, 476, 895, "16:45:45.476895", "\148\077\185\066\047\119\237\064" ; 3, 19, 23, 82, 343, "03:19:23.082343", "\007\038\055\138\138\093\199\064" ; 2, 52, 0, 568, 976, "02:52:00.568976", "\026\160\052\212\072\040\196\064" ; 1, 57, 14, 461, 5, "01:57:14.461005", "\075\118\108\004\118\122\187\064" ; 13, 32, 26, 933, 122, "13:32:26.933122", "\037\171\034\220\093\205\231\064" ; 1, 9, 39, 249, 395, "01:09:39.249395", "\201\200\089\216\063\083\176\064" ; 22, 15, 18, 204, 418, "22:15:18.204418", "\011\207\075\069\099\143\243\064" ; 1, 19, 15, 340, 787, "01:19:15.340787", "\231\027\209\061\087\147\178\064" ; 7, 1, 50, 166, 172, "07:01:50.166172", "\097\226\143\162\138\183\216\064" ; 21, 30, 40, 443, 960, "21:30:40.443960", "\012\205\117\026\007\232\242\064" ; 15, 45, 26, 637, 398, "15:45:26.637398", "\145\125\144\101\212\178\235\064" ; 22, 14, 32, 34, 730, "22:14:32.034730", "\099\011\065\142\128\140\243\064" ; 1, 25, 25, 581, 286, "01:25:25.581286", "\160\199\040\207\148\005\180\064" ; 19, 51, 20, 231, 163, "19:51:20.231163", "\081\249\215\178\131\115\241\064" ; 4, 26, 9, 984, 548, "04:26:09.984548", "\172\058\171\005\254\048\207\064" ; 22, 59, 56, 718, 823, "22:59:56.718823", "\201\139\076\128\203\054\244\064" ; 4, 4, 28, 269, 48, "04:04:28.269048", "\135\052\042\112\034\166\204\064" ; 8, 43, 54, 657, 184, "08:43:54.657184", "\221\122\077\015\170\178\222\064" ; 18, 19, 12, 781, 810, "18:19:12.781810", "\219\051\075\130\012\026\240\064" ; 22, 30, 1, 801, 84, "22:30:01.801084", "\214\116\061\209\156\198\243\064" ; 11, 12, 29, 994, 713, "11:12:29.994713", "\125\091\176\212\191\179\227\064" ; 17, 38, 27, 606, 608, "17:38:27.606608", "\048\046\085\105\115\002\239\064" ; 10, 30, 52, 322, 798, "10:30:52.322798", "\167\120\092\084\138\123\226\064" ; 17, 19, 7, 292, 786, "17:19:07.292786", "\215\190\128\094\105\113\238\064" ; 4, 51, 52, 12, 1, "04:51:52.012001", "\161\215\159\196\000\026\209\064" ; 14, 42, 48, 258, 581, "14:42:48.258581", "\076\169\075\070\008\221\233\064" ; 5, 47, 9, 901, 795, "05:47:09.901795", "\045\096\002\183\121\087\212\064" ; 16, 56, 45, 777, 958, "16:56:45.777958", "\245\044\008\229\184\201\237\064" ; 17, 41, 59, 892, 117, "17:41:59.892117", "\103\243\056\140\252\028\239\064" ; 15, 33, 30, 10, 737, "15:33:30.010737", "\252\030\245\087\064\089\235\064" ; 6, 1, 45, 62, 392, "06:01:45.062392", "\227\003\059\254\067\050\213\064" ; 15, 21, 0, 332, 14, "15:21:00.332014", "\250\210\219\159\138\251\234\064" ; 13, 36, 50, 734, 332, "13:36:50.734332", "\141\210\165\127\087\238\231\064" ; 21, 55, 40, 394, 997, "21:55:40.394997", "\208\095\232\081\198\069\243\064" ; 12, 15, 50, 911, 722, "12:15:50.911722", "\161\157\211\044\221\142\229\064" ; 13, 59, 5, 504, 639, "13:59:05.504639", "\041\176\000\038\048\149\232\064" ; 2, 55, 5, 104, 902, "02:55:05.104902", "\164\193\109\109\141\132\196\064" ; 19, 25, 32, 249, 693, "19:25:32.249693", "\080\022\190\254\195\018\241\064" ; 6, 32, 3, 671, 522, "06:32:03.671522", "\034\105\055\250\234\248\214\064" ; 15, 6, 14, 557, 910, "15:06:14.557910", "\132\018\102\218\209\140\234\064" ; 23, 30, 34, 626, 18, "23:30:34.626018", "\076\115\043\004\170\169\244\064" ; 20, 8, 54, 561, 687, "20:08:54.561687", "\250\129\171\252\104\181\241\064" ; 7, 23, 31, 965, 306, "07:23:31.965306", "\041\209\146\199\253\252\217\064" ; 2, 8, 1, 389, 763, "02:08:01.389763", "\049\010\130\199\099\001\190\064" ; 4, 48, 16, 132, 534, "04:48:16.132534", "\231\226\111\123\008\228\208\064" ; 22, 17, 53, 980, 658, "22:17:53.980658", "\105\113\198\176\031\153\243\064" ; 13, 56, 21, 49, 16, "13:56:21.049016", "\159\000\138\145\161\128\232\064" ; 3, 44, 31, 983, 896, "03:44:31.983896", "\085\219\077\240\253\079\202\064" ; 12, 34, 53, 54, 381, "12:34:53.054381", "\016\057\125\189\161\029\230\064" ; 8, 13, 14, 941, 943, "08:13:14.941943", "\236\074\203\072\188\230\220\064" ; 22, 52, 47, 927, 393, "22:52:47.927393", "\216\010\154\214\254\027\244\064" ; 16, 47, 28, 118, 463, "16:47:28.118463", "\217\234\114\202\003\132\237\064" ; 18, 21, 26, 51, 730, "18:21:26.051730", "\036\214\226\211\096\034\240\064" ; 16, 9, 56, 572, 280, "16:09:56.572280", "\133\037\030\080\146\106\236\064" ; 15, 42, 38, 751, 110, "15:42:38.751110", "\182\214\023\009\216\157\235\064" ; 16, 52, 25, 517, 935, "16:52:25.517935", "\206\107\236\146\048\169\237\064" ; 1, 26, 9, 313, 652, "01:26:09.313652", "\083\090\127\075\080\049\180\064" ; 15, 49, 51, 668, 965, "15:49:51.668965", "\165\073\041\104\245\211\235\064" ; 18, 52, 23, 867, 968, "18:52:23.867968", "\223\105\050\227\125\150\240\064" ; 14, 46, 52, 907, 909, "14:46:52.907909", "\216\044\151\013\157\251\233\064" ; 0, 45, 27, 596, 611, "00:45:27.596611", "\222\058\255\118\049\079\165\064" ; 7, 26, 14, 295, 266, "07:26:14.295266", "\103\093\163\229\146\037\218\064" ; 1, 50, 12, 268, 243, "01:50:12.268243", "\098\192\146\171\068\212\185\064" ; 2, 4, 43, 101, 322, "02:04:43.101322", "\093\020\061\240\025\059\189\064" ; 3, 56, 58, 718, 187, "03:56:58.718187", "\181\054\141\237\091\197\203\064" ; 19, 27, 12, 251, 116, "19:27:12.251116", "\248\053\146\004\004\025\241\064" ; 9, 35, 24, 678, 593, "09:35:24.678593", "\201\170\008\183\149\219\224\064" ; 0, 34, 21, 116, 671, "00:34:21.116671", "\200\034\077\188\059\026\160\064" ; 5, 42, 23, 156, 584, "05:42:23.156584", "\197\229\120\005\202\015\212\064" ; 7, 19, 43, 399, 402, "07:19:43.399402", "\254\103\205\143\217\195\217\064" ; 4, 25, 2, 608, 932, "04:25:02.608932", "\191\216\123\241\077\015\207\064" ; 15, 28, 30, 426, 416, "15:28:30.426416", "\208\042\051\165\205\051\235\064" ; 3, 59, 37, 506, 963, "03:59:37.506963", "\164\224\041\228\192\020\204\064" ; 0, 14, 46, 85, 499, "00:14:46.085499", "\186\134\025\026\175\176\139\064" ; 10, 13, 48, 231, 594, "10:13:48.231594", "\254\209\055\105\135\251\225\064" ; 20, 21, 19, 801, 223, "20:21:19.801223", "\093\053\207\209\252\227\241\064" ; 3, 53, 29, 298, 109, "03:53:29.298109", "\211\138\111\040\166\092\203\064" ; 22, 3, 2, 666, 436, "22:03:02.666436", "\142\203\184\169\106\097\243\064" ; 6, 50, 43, 908, 380, "06:50:43.908380", "\022\222\229\034\250\016\216\064" ; 7, 19, 45, 911, 980, "07:19:45.911980", "\167\092\225\093\122\196\217\064" ; 13, 26, 50, 270, 41, "13:26:50.270041", "\242\005\045\164\072\163\231\064" ; 2, 51, 23, 222, 261, "02:51:23.222261", "\022\103\012\115\156\021\196\064" ; 10, 36, 43, 177, 659, "10:36:43.177659", "\091\237\097\175\101\167\226\064" ; 12, 8, 4, 224, 250, "12:08:04.224250", "\004\086\014\045\135\084\229\064" ; 10, 0, 25, 54, 232, "10:00:25.054232", "\076\191\068\188\033\151\225\064" ; 6, 27, 12, 572, 107, "06:27:12.572107", "\180\173\102\157\036\176\214\064" ; 3, 43, 28, 515, 778, "03:43:28.515778", "\255\116\003\005\066\048\202\064" ; 15, 7, 18, 620, 962, "15:07:18.620962", "\066\179\235\222\211\148\234\064" ; 13, 39, 18, 343, 867, "13:39:18.343867", "\230\093\245\000\203\000\232\064" ; 7, 30, 10, 740, 704, "07:30:10.740704", "\001\192\177\103\175\096\218\064" ; 13, 52, 6, 595, 390, "13:52:06.595390", "\076\084\111\013\211\096\232\064" ; 0, 52, 31, 906, 98, "00:52:31.906098", "\241\185\019\236\207\159\168\064" ; 20, 1, 26, 43, 812, "20:01:26.043812", "\051\054\116\179\096\153\241\064" ; 9, 41, 34, 559, 146, "09:41:34.559146", "\246\038\134\228\209\009\225\064" ; 2, 58, 34, 674, 975, "02:58:34.674975", "\080\175\148\101\086\237\196\064" ; 12, 40, 50, 602, 226, "12:40:50.602226", "\217\117\111\069\083\074\230\064" ; 6, 50, 51, 208, 92, "06:50:51.208092", "\163\027\097\081\205\018\216\064" ; 0, 4, 3, 994, 129, "00:04:03.994129", "\042\224\158\231\207\127\110\064" ; 14, 27, 43, 840, 68, "14:27:43.840068", "\077\073\214\225\250\107\233\064" ; 17, 25, 7, 941, 230, "17:25:07.941230", "\128\096\142\030\126\158\238\064" ; 0, 18, 51, 393, 247, "00:18:51.393247", "\000\113\087\175\146\173\145\064" ; 15, 26, 56, 986, 809, "15:26:56.986809", "\204\119\240\147\031\040\235\064" ; 0, 47, 38, 502, 212, "00:47:38.502212", "\081\103\238\033\001\085\166\064" ; 17, 50, 39, 473, 563, "17:50:39.473563", "\179\151\109\039\239\093\239\064" ; 5, 15, 56, 10, 713, "05:15:56.010713", "\041\148\133\175\000\131\210\064" ; 21, 18, 40, 500, 794, "21:18:40.500794", "\193\145\064\003\008\187\242\064" ; 17, 11, 13, 632, 259, "17:11:13.632259", "\243\057\119\059\052\054\238\064" ; 23, 20, 22, 288, 390, "23:20:22.288390", "\040\213\062\157\100\131\244\064" ; 17, 8, 39, 209, 528, "17:08:39.209528", "\115\016\116\180\230\034\238\064" ; 5, 49, 51, 541, 620, "05:49:51.541620", "\183\238\230\169\226\127\212\064" ; 1, 50, 17, 471, 724, "01:50:17.471724", "\189\112\231\194\120\217\185\064" ; 14, 44, 20, 463, 715, "14:44:20.463715", "\246\214\192\214\142\232\233\064" ; 13, 50, 11, 669, 647, "13:50:11.669647", "\156\139\191\109\117\082\232\064" ; 19, 13, 59, 638, 150, "19:13:59.638150", "\064\198\220\053\122\231\240\064" ; 1, 57, 53, 894, 734, "01:57:53.894734", "\159\148\073\013\229\161\187\064" ; 21, 36, 25, 6, 962, "21:36:25.006962", "\165\047\132\028\144\253\242\064" ; 7, 2, 16, 446, 107, "07:02:16.446107", "\225\095\004\141\028\190\216\064" ; 0, 18, 12, 124, 614, "00:18:12.124614", "\127\250\207\154\127\016\145\064" ; 15, 12, 20, 502, 288, "15:12:20.502288", "\166\072\190\018\144\186\234\064" ; 13, 31, 8, 301, 554, "13:31:08.301554", "\255\146\084\166\137\195\231\064" ; 3, 17, 58, 7, 576, "03:17:58.007576", "\030\024\064\248\000\051\199\064" ; 7, 53, 20, 266, 182, "07:53:20.266182", "\050\058\032\009\017\188\219\064" ; 0, 39, 14, 698, 198, "00:39:14.698198", "\068\080\053\122\101\101\162\064" ; 21, 26, 53, 330, 423, "21:26:53.330423", "\174\160\105\073\213\217\242\064" ; 6, 28, 5, 37, 157, "06:28:05.037157", "\244\192\199\096\066\189\214\064" ; 18, 33, 54, 624, 709, "18:33:54.624709", "\072\221\206\254\041\081\240\064" ; 11, 32, 58, 3, 295, "11:32:58.003295", "\167\029\254\026\064\077\228\064" ; 21, 22, 31, 740, 492, "21:22:31.740492", "\176\035\014\217\123\201\242\064" ; 15, 34, 21, 41, 426, "15:34:21.041426", "\102\158\092\083\161\095\235\064" ; 3, 33, 8, 17, 561, "03:33:08.017561", "\088\088\112\063\002\250\200\064" ; 19, 18, 40, 392, 260, "19:18:40.392260", "\249\107\178\070\006\249\240\064" ; 19, 23, 11, 998, 369, "19:23:11.998369", "\198\197\081\249\255\009\241\064" ; 12, 23, 19, 1, 724, "12:23:19.001724", "\115\125\031\014\224\198\229\064" ; 16, 24, 32, 124, 263, "16:24:32.124263", "\036\102\246\249\003\216\236\064" ; 21, 13, 32, 926, 886, "21:13:32.926886", "\018\106\134\212\206\167\242\064" ; 14, 1, 29, 690, 6, "14:01:29.690006", "\130\118\135\020\054\167\232\064" ; 4, 24, 14, 402, 66, "04:24:14.402066", "\107\016\230\118\051\247\206\064" ; 5, 3, 18, 689, 566, "05:03:18.689566", "\155\110\217\033\172\197\209\064" ; 22, 16, 25, 59, 108, "22:16:25.059108", "\238\058\027\242\144\147\243\064" ; 9, 53, 44, 66, 609, "09:53:44.066609", "\148\050\169\033\002\101\225\064" ; 14, 50, 44, 4, 287, "14:50:44.004287", "\154\125\030\035\128\024\234\064" ; 18, 29, 56, 153, 421, "18:29:56.153421", "\025\148\105\116\066\066\240\064" ; 21, 35, 25, 330, 624, "21:35:25.330624", "\052\100\060\074\213\249\242\064" ; 13, 56, 5, 755, 647, "13:56:05.755647", "\010\158\066\046\184\126\232\064" ; 16, 16, 26, 400, 237, "16:16:26.400237", "\053\211\189\206\076\155\236\064" ; 4, 9, 26, 206, 135, "04:09:26.206135", "\200\181\161\098\026\059\205\064" ; 19, 28, 0, 855, 727, "19:28:00.855727", "\117\203\014\177\013\028\241\064" ; 6, 43, 44, 522, 159, "06:43:44.522159", "\020\149\013\107\033\168\215\064" ; 17, 31, 20, 506, 209, "17:31:20.506209", "\126\055\221\050\016\205\238\064" ; 23, 41, 15, 221, 478, "23:41:15.221478", "\237\131\044\139\179\209\244\064" ; 16, 40, 57, 826, 480, "16:40:57.826480", "\090\047\134\114\058\083\237\064" ; 21, 35, 33, 127, 584, "21:35:33.127584", "\055\133\149\010\082\250\242\064" ; 18, 27, 40, 544, 104, "18:27:40.544104", "\090\101\166\180\200\057\240\064" ; 7, 16, 21, 135, 643, "07:16:21.135643", "\059\250\095\174\072\145\217\064" ; 16, 53, 9, 809, 293, "16:53:09.809293", "\252\110\186\229\185\174\237\064" ; 3, 3, 13, 627, 851, "03:03:13.627851", "\226\235\107\093\208\120\197\064" ; 1, 57, 24, 456, 413, "01:57:24.456413", "\120\124\123\215\116\132\187\064" ; 1, 49, 32, 251, 804, "01:49:32.251804", "\001\025\058\118\064\172\185\064" ; 1, 47, 57, 70, 456, "01:47:57.070456", "\206\135\103\009\018\077\185\064" ; 4, 39, 29, 671, 336, "04:39:29.671336", "\040\069\043\247\106\096\208\064" ; 8, 42, 5, 262, 729, "08:42:05.262729", "\173\075\141\208\080\151\222\064" ; 1, 50, 32, 918, 82, "01:50:32.918082", "\011\005\108\007\235\232\185\064" ; 12, 0, 25, 232, 775, "12:00:25.232775", "\139\142\228\114\039\027\229\064" ; 1, 54, 0, 690, 798, "01:54:00.690798", "\036\066\035\216\176\184\186\064" ; 4, 32, 52, 650, 432, "04:32:52.650432", "\035\020\091\065\083\250\207\064" ; 2, 47, 58, 899, 100, "02:47:58.899100", "\234\115\181\021\115\175\195\064" ; 9, 42, 10, 438, 179, "09:42:10.438179", "\090\247\143\005\078\014\225\064" ; 17, 8, 57, 519, 653, "17:08:57.519653", "\009\084\255\160\048\037\238\064" ; 17, 28, 15, 819, 266, "17:28:15.819266", "\152\084\109\055\250\181\238\064" ; 18, 27, 45, 525, 573, "18:27:45.525573", "\234\059\191\104\024\058\240\064" ; 11, 27, 39, 19, 400, "11:27:39.019400", "\177\191\236\158\096\037\228\064" ; 9, 26, 48, 970, 738, "09:26:48.970738", "\096\035\073\016\031\155\224\064" ; 11, 16, 0, 296, 661, "11:16:00.296661", "\160\053\063\126\009\206\227\064" ; 1, 38, 31, 828, 337, "01:38:31.828337", "\018\197\228\013\212\023\183\064" ; 10, 19, 47, 948, 284, "10:19:47.948284", "\234\175\087\088\126\040\226\064" ; 12, 17, 3, 311, 289, "12:17:03.311289", "\084\089\020\246\233\151\229\064" ; 6, 54, 36, 479, 633, "06:54:36.479633", "\069\156\078\178\030\075\216\064" ; 4, 27, 58, 229, 819, "04:27:58.229819", "\128\128\181\106\029\103\207\064" ; 6, 9, 30, 762, 271, "06:09:30.762271", "\236\077\012\201\176\166\213\064" ; 17, 22, 22, 427, 114, "17:22:22.427114", "\182\250\234\170\205\137\238\064" ; 17, 9, 51, 326, 694, "17:09:51.326694", "\186\249\070\116\234\043\238\064" ; 20, 23, 53, 571, 672, "20:23:53.571672", "\000\138\145\037\153\237\241\064" ; 7, 28, 39, 512, 337, "07:28:39.512337", "\226\032\033\202\224\073\218\064" ; 18, 36, 48, 879, 276, "18:36:48.879276", "\003\182\131\017\014\092\240\064" ; 17, 42, 25, 859, 341, "17:42:25.859341", "\099\178\184\127\059\032\239\064" ; 20, 40, 56, 209, 209, "20:40:56.209209", "\081\137\235\088\131\045\242\064" ; 2, 31, 17, 419, 693, "02:31:17.419693", "\174\014\128\184\181\186\193\064" ; 2, 1, 44, 122, 280, "02:01:44.122280", "\245\248\189\077\031\136\188\064" ; 22, 34, 4, 605, 698, "22:34:04.605698", "\212\098\240\176\201\213\243\064" ; 0, 18, 17, 829, 368, "00:18:17.829368", "\101\081\216\069\081\039\145\064" ; 22, 53, 56, 872, 377, "22:53:56.872377", "\205\149\065\245\077\032\244\064" ; 14, 33, 40, 309, 592, "14:33:40.309592", "\099\123\045\232\137\152\233\064" ; 9, 43, 55, 852, 10, "09:43:55.852010", "\188\121\170\067\123\027\225\064" ; 0, 21, 56, 216, 48, "00:21:56.216048", "\119\217\175\059\221\144\148\064" ; 20, 23, 40, 503, 164, "20:23:40.503164", "\200\177\245\012\200\236\241\064" ; 19, 11, 35, 388, 747, "19:11:35.388747", "\055\198\078\056\118\222\240\064" ; 8, 2, 8, 56, 528, "08:02:08.056528", "\212\157\039\158\003\064\220\064" ; 5, 50, 19, 299, 166, "05:50:19.299166", "\133\038\137\037\211\134\212\064" ; 8, 28, 28, 658, 691, "08:28:28.658691", "\203\075\254\039\042\203\221\064" ; 0, 27, 55, 518, 965, "00:27:55.518965", "\019\155\143\107\019\046\154\064" ; 10, 55, 44, 591, 565, "10:55:44.591565", "\015\185\025\238\018\054\227\064" ; 23, 51, 25, 349, 894, "23:51:25.349894", "\113\115\042\153\213\247\244\064" ; 3, 49, 19, 993, 889, "03:49:19.993889", "\110\055\193\055\255\223\202\064" ; 8, 28, 59, 549, 151, "08:28:59.549151", "\100\060\074\037\227\210\221\064" ; 10, 42, 45, 911, 166, "10:42:45.911166", "\103\153\069\040\189\212\226\064" ; 1, 51, 12, 869, 768, "01:51:12.869768", "\027\155\029\169\222\016\186\064" ; 15, 59, 37, 24, 295, "15:59:37.024295", "\206\078\006\199\032\029\236\064" ; 2, 46, 4, 175, 697, "02:46:04.175697", "\128\066\061\125\022\118\195\064" ; 23, 34, 53, 945, 579, "23:34:53.945579", "\013\114\023\033\223\185\244\064" ; 19, 32, 8, 904, 189, "19:32:08.904189", "\134\226\142\119\142\043\241\064" ; 23, 52, 54, 713, 941, "23:52:54.713941", "\229\101\077\108\107\253\244\064" ; 12, 53, 55, 516, 737, "12:53:55.516737", "\117\008\028\137\112\172\230\064" ; 19, 0, 45, 746, 245, "19:00:45.746245", "\221\152\158\240\219\181\240\064" ; 2, 25, 2, 736, 56, "02:25:02.736056", "\004\064\021\055\094\255\192\064" ; 4, 21, 15, 752, 494, "04:21:15.752494", "\056\048\185\081\224\157\206\064" ; 8, 26, 25, 870, 600, "08:26:25.870600", "\249\015\233\183\119\172\221\064" ; 8, 34, 41, 454, 802, "08:34:41.454802", "\010\217\121\027\093\040\222\064" ; 1, 27, 46, 249, 812, "01:27:46.249812", "\038\226\173\243\063\146\180\064" ; 18, 23, 36, 63, 904, "18:23:36.063904", "\097\051\192\005\129\042\240\064" ; 17, 12, 32, 59, 676, "17:12:32.059676", "\140\164\221\232\001\064\238\064" ; 1, 35, 15, 871, 467, "01:35:15.871467", "\139\024\118\024\223\083\182\064" ; 15, 3, 4, 320, 577, "15:03:04.320577", "\091\178\042\066\010\117\234\064" ; 19, 37, 50, 532, 283, "19:37:50.532283", "\212\045\059\132\232\064\241\064" ; 7, 22, 50, 160, 687, "07:22:50.160687", "\121\032\178\072\138\242\217\064" ; 7, 3, 14, 733, 429, "07:03:14.733429", "\060\048\128\240\174\204\216\064" ; 20, 36, 28, 206, 941, "20:36:28.206941", "\180\093\161\079\195\028\242\064" ; 22, 47, 56, 648, 61, "22:47:56.648061", "\013\054\117\094\202\009\244\064" ; 8, 27, 38, 18, 191, "08:27:38.018191", "\133\149\010\042\129\190\221\064" ; 1, 7, 41, 66, 47, "01:07:41.066047", "\255\145\233\208\033\186\175\064" ; 4, 4, 13, 905, 320, "04:04:13.905320", "\053\152\134\225\243\158\204\064" ; 20, 20, 7, 436, 685, "20:20:07.436685", "\027\105\169\252\118\223\241\064" ; 4, 40, 44, 210, 397, "04:40:44.210397", "\139\250\036\119\013\115\208\064" ; 5, 59, 15, 719, 307, "05:59:15.719307", "\050\058\032\009\238\012\213\064" ; 16, 24, 38, 490, 721, "16:24:38.490721", "\206\134\252\179\207\216\236\064" ; 13, 54, 49, 580, 977, "13:54:49.580977", "\216\019\093\151\050\117\232\064" ; 23, 15, 25, 574, 264, "23:15:25.574264", "\180\114\047\048\217\112\244\064" ; 17, 14, 17, 12, 80, "17:14:17.012080", "\158\152\245\098\032\077\238\064" ; 19, 41, 42, 96, 338, "19:41:42.096338", "\246\182\153\138\097\079\241\064" ; 14, 21, 39, 224, 786, "14:21:39.224786", "\211\104\114\049\103\062\233\064" ; 21, 5, 16, 876, 937, "21:05:16.876937", "\123\023\239\007\206\136\242\064" ; 20, 58, 43, 398, 614, "20:58:43.398614", "\220\018\185\096\054\112\242\064" ; 10, 0, 11, 76, 816, "10:00:11.076816", "\250\211\070\117\098\149\225\064" ; 17, 29, 49, 372, 468, "17:29:49.372468", "\218\002\066\235\171\193\238\064" ; 6, 12, 21, 764, 713, "06:12:21.764713", "\117\203\014\241\112\209\213\064" ; 15, 37, 7, 719, 418, "15:37:07.719418", "\197\229\120\005\119\116\235\064" ; 8, 33, 4, 542, 319, "08:33:04.542319", "\064\192\090\181\034\016\222\064" ; 10, 50, 29, 793, 701, "10:50:29.793701", "\185\163\255\101\185\014\227\064" ; 21, 3, 2, 437, 769, "21:03:02.437769", "\036\017\026\001\103\128\242\064" ; 8, 24, 44, 134, 328, "08:24:44.134328", "\187\119\212\152\008\147\221\064" ; 16, 32, 43, 593, 773, "16:32:43.593773", "\008\060\048\000\115\021\237\064" ; 22, 9, 41, 876, 6, "22:09:41.876006", "\018\222\030\004\094\122\243\064" ; 7, 11, 8, 20, 843, "07:11:08.020843", "\215\224\125\085\001\067\217\064" ; 2, 8, 24, 37, 662, "02:08:24.037662", "\078\130\055\164\009\024\190\064" ; 15, 39, 54, 838, 41, "15:39:54.838041", "\247\091\059\209\090\137\235\064" ; 0, 31, 21, 23, 441, "00:31:21.023441", "\138\225\234\000\024\100\157\064" ; 23, 50, 2, 444, 210, "23:50:02.444210", "\233\241\123\027\167\242\244\064" ; 1, 41, 47, 36, 26, "01:41:47.036026", "\206\251\255\056\009\219\183\064" ; 3, 45, 57, 489, 467, "03:45:57.489467", "\188\202\218\166\190\122\202\064" ; 19, 35, 36, 217, 924, "19:35:36.217924", "\081\224\157\124\131\056\241\064" ; 19, 16, 50, 982, 6, "19:16:50.982006", "\104\236\075\182\047\242\240\064" ; 3, 20, 20, 587, 737, "03:20:20.587737", "\211\076\247\058\075\122\199\064" ; 19, 38, 56, 790, 93, "19:38:56.790093", "\188\142\056\164\012\069\241\064" ; 2, 18, 52, 496, 590, "02:18:52.496590", "\194\216\066\144\063\070\192\064" ; 11, 50, 22, 423, 266, "11:50:22.423266", "\113\035\101\139\205\207\228\064" ; 16, 13, 51, 992, 423, "16:13:51.992423", "\025\225\237\193\255\135\236\064" ; 0, 56, 40, 387, 241, "00:56:40.387241", "\088\205\115\068\198\144\170\064" ; 14, 8, 11, 858, 294, "14:08:11.858294", "\139\250\036\119\123\217\232\064" ; 5, 24, 26, 977, 89, "05:24:26.977089", "\018\077\160\136\190\002\211\064" ; 18, 21, 41, 141, 971, "18:21:41.141971", "\032\098\131\069\082\035\240\064" ; 9, 51, 36, 328, 345, "09:51:36.328345", "\154\095\205\129\010\085\225\064" ; 13, 5, 15, 514, 553, "13:05:15.514553", "\098\218\055\119\112\001\231\064" ; 0, 30, 24, 415, 567, "00:30:24.415567", "\048\073\101\138\169\129\156\064" ; 11, 16, 5, 29, 254, "11:16:05.029254", "\169\021\166\239\160\206\227\064" ; 11, 42, 58, 839, 685, "11:42:58.839685", "\190\019\179\222\090\152\228\064" ; 13, 51, 25, 949, 544, "13:51:25.949544", "\068\025\170\098\190\091\232\064" ; 16, 20, 13, 975, 270, "16:20:13.975270", "\088\110\105\053\191\183\236\064" ; 19, 48, 35, 96, 850, "19:48:35.096850", "\234\149\178\140\049\105\241\064" ; 11, 26, 16, 338, 603, "11:26:16.338603", "\107\245\213\213\010\027\228\064" ; 8, 39, 5, 100, 840, "08:39:05.100840", "\136\157\041\116\070\106\222\064" ; 18, 10, 51, 770, 786, "18:10:51.770786", "\198\102\071\170\120\245\239\064" ; 8, 24, 50, 110, 874, "08:24:50.110874", "\255\066\143\024\135\148\221\064" ; 5, 3, 1, 474, 197, "05:03:01.474197", "\183\095\062\089\094\193\209\064" ; 0, 53, 8, 373, 295, "00:53:08.373295", "\133\177\133\032\191\232\168\064" ; 12, 36, 47, 229, 297, "12:36:47.229297", "\130\169\102\086\231\043\230\064" ; 6, 13, 4, 605, 144, "06:13:04.605144", "\088\230\173\186\038\220\213\064" ; 8, 47, 32, 642, 207, "08:47:32.642207", "\145\099\235\025\041\233\222\064" ; 9, 8, 49, 870, 606, "09:08:49.870606", "\055\029\001\220\059\020\224\064" ; 10, 5, 4, 738, 751, "10:05:04.738751", "\028\035\217\163\023\186\225\064" ; 13, 8, 1, 80, 490, "13:08:01.080490", "\181\195\095\147\034\022\231\064" ; 10, 40, 8, 252, 494, "10:40:08.252494", "\014\076\110\020\008\193\226\064" ; 12, 53, 30, 747, 134, "12:53:30.747134", "\248\143\133\232\087\169\230\064" ; 20, 58, 46, 424, 589, "20:58:46.424589", "\212\213\029\203\102\112\242\064" ; 19, 15, 1, 851, 281, "19:15:01.851281", "\107\211\216\158\093\235\240\064" ; 15, 48, 35, 953, 367, "15:48:35.953367", "\195\130\251\129\126\202\235\064" ; 2, 36, 16, 450, 220, "02:36:16.450220", "\001\024\207\160\057\080\194\064" ; 7, 40, 29, 455, 966, "07:40:29.455966", "\134\004\140\046\093\251\218\064" ; 6, 5, 32, 468, 563, "06:05:32.468563", "\072\170\239\252\029\107\213\064" ; 6, 37, 21, 354, 560, "06:37:21.354560", "\030\109\028\177\086\072\215\064" ; 23, 0, 58, 455, 976, "23:00:58.455976", "\124\125\173\075\167\058\244\064" ; 18, 30, 12, 781, 847, "18:30:12.781847", "\248\255\113\130\076\067\240\064" ; 8, 20, 10, 77, 641, "08:20:10.077641", "\245\244\017\248\132\078\221\064" ; 21, 35, 47, 672, 318, "21:35:47.672318", "\233\132\208\193\058\251\242\064" ; 1, 8, 38, 374, 451, "01:08:38.374451", "\244\078\005\220\095\022\176\064" ; 8, 57, 9, 776, 13, "08:57:09.776013", "\018\110\050\170\113\121\223\064" ; 22, 27, 12, 835, 500, "22:27:12.835500", "\125\063\053\094\013\188\243\064" ; 13, 14, 11, 579, 197, "13:14:11.579197", "\158\037\200\136\114\068\231\064" ; 18, 34, 32, 41, 437, "18:34:32.041437", "\253\215\185\169\128\083\240\064" ; 15, 4, 39, 189, 622, "15:04:39.189622", "\019\040\098\017\230\128\234\064" ; 22, 41, 14, 444, 844, "22:41:14.444844", "\253\189\020\030\167\240\243\064" ; 23, 30, 37, 504, 259, "23:30:37.504259", "\155\226\113\017\216\169\244\064" ; 3, 26, 28, 100, 716, "03:26:28.100716", "\024\011\067\228\012\050\200\064" ; 13, 43, 44, 598, 604, "13:43:44.598604", "\104\147\195\039\019\034\232\064" ; 0, 59, 40, 497, 594, "00:59:40.497594", "\095\009\164\196\254\248\171\064" ; 21, 20, 49, 165, 687, "21:20:49.165687", "\102\105\167\166\018\195\242\064" ; 1, 36, 48, 737, 966, "01:36:48.737966", "\143\251\086\235\188\176\182\064" ; 1, 36, 58, 249, 546, "01:36:58.249546", "\217\036\063\226\063\186\182\064" ; 3, 19, 41, 372, 245, "03:19:41.372245", "\140\098\185\165\175\102\199\064" ; 19, 11, 1, 14, 699, "19:11:01.014699", "\196\004\053\060\080\220\240\064" ; 19, 28, 46, 548, 107, "19:28:46.548107", "\123\216\011\197\232\030\241\064" ; 12, 30, 39, 409, 952, "12:30:39.409952", "\030\168\083\030\237\253\229\064" ; 20, 30, 27, 917, 626, "20:30:27.917626", "\191\153\152\174\062\006\242\064" ; 23, 45, 48, 271, 254, "23:45:48.271254", "\046\111\014\087\196\226\244\064" ; 17, 49, 26, 178, 719, "17:49:26.178719", "\134\232\016\184\197\084\239\064" ; 21, 46, 36, 40, 929, "21:46:36.040929", "\199\042\165\167\192\035\243\064" ; 19, 28, 38, 797, 670, "19:28:38.797670", "\048\158\065\195\108\030\241\064" ; 7, 24, 32, 287, 292, "07:24:32.287292", "\026\252\253\098\018\012\218\064" ; 2, 36, 2, 93, 359, "02:36:02.093359", "\229\013\048\243\011\073\194\064" ; 19, 35, 43, 231, 34, "19:35:43.231034", "\036\181\080\178\243\056\241\064" ; 20, 45, 20, 756, 432, "20:45:20.756432", "\218\112\088\026\012\062\242\064" ; 9, 17, 22, 59, 766, "09:17:22.059766", "\237\098\154\233\065\084\224\064" ; 11, 26, 57, 182, 570, "11:26:57.182570", "\103\010\157\215\037\032\228\064" ; 6, 33, 13, 36, 364, "06:33:13.036364", "\176\171\201\083\066\010\215\064" ; 16, 20, 1, 381, 38, "16:20:01.381038", "\145\154\118\049\044\182\236\064" ; 1, 21, 47, 689, 641, "01:21:47.689641", "\251\004\080\140\176\043\179\064" ; 20, 29, 57, 747, 522, "20:29:57.747522", "\241\160\217\245\091\004\242\064" ; 18, 21, 57, 592, 289, "18:21:57.592289", "\205\007\004\122\089\036\240\064" ; 0, 15, 54, 955, 151, "00:15:54.955151", "\239\029\053\038\164\215\141\064" ; 0, 22, 48, 213, 664, "00:22:48.213664", "\084\081\188\202\218\096\149\064" ; 19, 10, 48, 407, 61, "19:10:48.407061", "\040\101\082\131\134\219\240\064" ; 15, 36, 39, 125, 728, "15:36:39.125728", "\006\186\246\005\228\112\235\064" ; 18, 1, 50, 733, 276, "18:01:50.733276", "\222\058\255\118\215\177\239\064" ; 11, 38, 48, 927, 681, "11:38:48.927681", "\132\016\144\175\029\121\228\064" ; 17, 18, 18, 674, 760, "17:18:18.674760", "\149\072\162\151\085\107\238\064" ; 6, 44, 19, 201, 213, "06:44:19.201213", "\162\125\172\224\204\176\215\064" ; 23, 5, 53, 200, 439, "23:05:53.200439", "\093\134\255\052\019\077\244\064" ; 8, 7, 11, 657, 39, "08:07:11.657039", "\076\078\237\012\234\139\220\064" ; 7, 16, 3, 479, 69, "07:16:03.479069", "\226\005\017\169\222\140\217\064" ; 2, 58, 49, 325, 281, "02:58:49.325281", "\130\204\206\162\169\244\196\064" ; 13, 14, 20, 814, 688, "13:14:20.814688", "\142\145\236\017\154\069\231\064" ; 4, 9, 54, 312, 812, "04:09:54.312812", "\230\062\057\010\040\073\205\064" ; 11, 39, 38, 101, 957, "11:39:38.101957", "\147\083\059\067\067\127\228\064" ; 7, 10, 58, 856, 299, "07:10:58.856299", "\038\082\154\205\182\064\217\064" ; 11, 46, 36, 129, 909, "11:46:36.129909", "\079\235\054\040\132\179\228\064" ; 12, 13, 36, 780, 642, "12:13:36.780642", "\124\238\004\251\024\126\229\064" ; 23, 42, 39, 940, 646, "23:42:39.940646", "\242\209\226\012\255\214\244\064" ; 18, 0, 31, 685, 272, "18:00:31.685272", "\155\139\191\237\245\167\239\064" ; 7, 27, 11, 648, 676, "07:27:11.648676", "\109\087\232\131\233\051\218\064" ; 0, 20, 40, 962, 285, "00:20:40.962285", "\186\049\061\097\217\099\147\064" ; 21, 33, 21, 700, 753, "21:33:21.700753", "\025\199\072\054\027\242\242\064" ; 10, 19, 21, 69, 951, "10:19:21.069951", "\043\225\009\061\034\037\226\064" ; 4, 20, 48, 631, 70, "04:20:48.631070", "\190\217\230\198\080\144\206\064" ; 5, 9, 18, 513, 845, "05:09:18.513845", "\141\035\214\226\160\031\210\064" ; 22, 57, 40, 519, 715, "22:57:40.519715", "\004\173\192\080\072\046\244\064" ; 16, 6, 32, 287, 135, "16:06:32.287135", "\081\189\053\048\009\081\236\064" ; 15, 24, 9, 382, 99, "15:24:09.382099", "\154\174\039\058\044\019\235\064" ; 2, 15, 53, 347, 260, "02:15:53.347260", "\053\007\008\230\088\217\191\064" ; 16, 46, 26, 516, 678, "16:46:26.516678", "\018\077\160\136\080\124\237\064" ; 13, 44, 21, 519, 79, "13:44:21.519079", "\033\144\075\156\176\038\232\064" ; 21, 52, 41, 685, 770, "21:52:41.685770", "\169\246\233\248\154\058\243\064" ; 13, 20, 51, 198, 833, "13:20:51.198833", "\011\006\215\092\102\118\231\064" ; 22, 19, 53, 387, 945, "22:19:53.387945", "\251\208\005\053\150\160\243\064" ; 17, 59, 40, 136, 742, "17:59:40.136742", "\063\194\048\096\132\161\239\064" ; 9, 22, 37, 106, 802, "09:22:37.106802", "\037\007\236\106\163\123\224\064" ; 7, 29, 9, 305, 371, "07:29:09.305371", "\137\206\050\139\083\081\218\064" ; 5, 51, 36, 653, 770, "05:51:36.653770", "\070\032\094\215\041\154\212\064" ; 13, 8, 21, 296, 8, "13:08:21.296008", "\236\196\229\120\169\024\231\064" ; 5, 18, 41, 195, 571, "05:18:41.195571", "\067\058\060\132\076\172\210\064" ; 22, 5, 20, 261, 168, "22:05:20.261168", "\044\127\190\045\004\106\243\064" ; 6, 11, 14, 377, 705, "06:11:14.377705", "\162\151\081\044\152\192\213\064" ; 19, 9, 29, 845, 352, "19:09:29.845352", "\154\209\143\134\157\214\240\064" ; 21, 37, 1, 168, 697, "21:37:01.168697", "\031\160\251\178\210\255\242\064" ; 21, 0, 13, 174, 468, "21:00:13.174468", "\035\245\158\202\210\117\242\064" ; 2, 8, 12, 18, 776, "02:08:12.018776", "\243\001\129\206\004\012\190\064" ; 1, 47, 51, 240, 498, "01:47:51.240498", "\193\228\070\145\061\071\185\064" ; 19, 22, 24, 785, 477, "19:22:24.785477", "\172\084\080\145\012\007\241\064" ; 19, 59, 4, 292, 422, "19:59:04.292422", "\234\176\194\173\132\144\241\064" ; 18, 2, 9, 218, 493, "18:02:09.218493", "\045\008\229\253\038\180\239\064" ; 8, 45, 59, 144, 804, "08:45:59.144804", "\021\255\119\068\201\209\222\064" ; 12, 58, 43, 479, 438, "12:58:43.479438", "\079\092\142\087\111\208\230\064" ; 4, 45, 56, 961, 388, "04:45:56.961388", "\177\136\097\135\061\193\208\064" ; 1, 36, 5, 58, 696, "01:36:05.058696", "\104\120\179\006\015\133\182\064" ; 13, 42, 55, 824, 302, "13:42:55.824302", "\129\150\174\096\250\027\232\064" ; 0, 26, 48, 579, 681, "00:26:48.579681", "\115\100\229\151\081\034\153\064" ; 23, 36, 43, 553, 90, "23:36:43.553090", "\092\230\116\217\184\192\244\064" ; 16, 36, 34, 947, 421, "16:36:34.947421", "\081\216\069\081\094\050\237\064" ; 12, 15, 43, 621, 963, "12:15:43.621963", "\010\243\030\231\243\141\229\064" ; 18, 28, 57, 878, 84, "18:28:57.878084", "\242\206\161\012\158\062\240\064" ; 4, 30, 38, 963, 107, "04:30:38.963107", "\198\021\023\071\123\183\207\064" ; 13, 39, 51, 319, 533, "13:39:51.319533", "\032\069\157\057\234\004\232\064" ; 11, 25, 10, 707, 938, "11:25:10.707938", "\179\151\109\167\214\018\228\064" ; 15, 20, 50, 366, 637, "15:20:50.366637", "\144\132\125\187\075\250\234\064" ; 22, 23, 19, 687, 158, "22:23:19.687158", "\019\099\153\254\122\173\243\064" ; 12, 51, 22, 445, 249, "12:51:22.445249", "\178\212\122\063\078\153\230\064" ; 2, 59, 42, 665, 254, "02:59:42.665254", "\197\006\011\039\085\015\197\064" ; 8, 9, 49, 76, 56, "08:09:49.076056", "\043\252\025\222\068\179\220\064" ; 10, 49, 37, 156, 820, "10:49:37.156820", "\108\096\171\004\037\008\227\064" ; 7, 14, 57, 709, 33, "07:14:57.709033", "\178\242\203\096\109\124\217\064" ; 6, 34, 25, 294, 622, "06:34:25.294622", "\172\059\022\219\082\028\215\064" ; 17, 28, 15, 154, 520, "17:28:15.154520", "\083\237\211\241\228\181\238\064" ; 9, 43, 25, 935, 847, "09:43:25.935847", "\098\104\117\242\189\023\225\064" ; 7, 34, 30, 285, 953, "07:34:30.285953", "\204\207\013\077\146\161\218\064" ; 0, 54, 53, 642, 59, "00:54:53.642059", "\052\014\245\187\072\187\169\064" ; 3, 25, 36, 620, 188, "03:25:36.620188", "\176\004\082\098\079\024\200\064" ; 18, 46, 36, 383, 286, "18:46:36.383286", "\048\128\240\033\198\128\240\064" ; 17, 58, 48, 925, 397, "17:58:48.925397", "\091\043\218\156\029\155\239\064" ; 8, 39, 4, 798, 766, "08:39:04.798766", "\202\109\251\030\051\106\222\064" ; 2, 15, 13, 366, 105, "02:15:13.366105", "\231\169\014\185\093\177\191\064" ; 23, 0, 40, 96, 161, "23:00:40.096161", "\227\029\224\137\129\057\244\064" ; 10, 12, 19, 144, 498, "10:12:19.144498", "\011\069\186\159\100\240\225\064" ; 15, 24, 36, 838, 840, "15:24:36.838840", "\211\251\198\215\154\022\235\064" ; 21, 0, 38, 377, 65, "21:00:38.377065", "\055\079\117\008\102\119\242\064" ; 19, 27, 6, 931, 885, "19:27:06.931885", "\234\062\000\233\174\024\241\064" ; 20, 23, 10, 295, 48, "20:23:10.295048", "\108\064\132\184\228\234\241\064" ; 12, 47, 0, 697, 185, "12:47:00.697185", "\200\234\086\079\150\120\230\064" ; 10, 49, 35, 270, 401, "10:49:35.270401", "\121\255\031\167\232\007\227\064" ; 21, 44, 15, 604, 601, "21:44:15.604601", "\035\025\114\172\249\026\243\064" ; 23, 47, 49, 398, 531, "23:47:49.398531", "\183\010\098\096\086\234\244\064" ; 5, 24, 22, 999, 817, "05:24:22.999817", "\063\113\000\253\191\001\211\064" ; 22, 0, 35, 232, 2, "22:00:35.232002", "\170\186\071\182\051\088\243\064" ; 0, 20, 49, 545, 160, "00:20:49.545160", "\090\076\108\062\046\134\147\064" ; 10, 47, 25, 929, 743, "10:47:25.929743", "\085\100\116\192\189\247\226\064" ; 6, 25, 59, 415, 431, "06:25:59.415431", "\176\231\107\150\218\157\214\064" ; 13, 22, 39, 198, 498, "13:22:39.198498", "\074\122\024\090\230\131\231\064" ; 6, 13, 1, 342, 708, "06:13:01.342708", "\005\137\237\238\085\219\213\064" ; 5, 34, 33, 930, 635, "05:34:33.930635", "\097\026\134\143\123\154\211\064" ; 6, 15, 8, 11, 714, "06:15:08.011714", "\186\019\236\191\000\251\213\064" ; 8, 30, 55, 720, 238, "08:30:55.720238", "\214\031\097\024\238\239\221\064" ; 19, 57, 46, 201, 539, "19:57:46.201539", "\094\245\128\057\163\139\241\064" ; 10, 17, 13, 643, 625, "10:17:13.643625", "\188\116\147\152\052\021\226\064" ; 1, 4, 19, 651, 439, "01:04:19.651439", "\173\160\105\137\077\039\174\064" ; 17, 7, 7, 524, 448, "17:07:07.524448", "\014\044\071\200\112\023\238\064" ; 7, 9, 38, 285, 956, "07:09:38.285956", "\006\101\026\077\146\044\217\064" ; 6, 26, 30, 16, 107, "06:26:30.016107", "\143\167\229\007\129\165\214\064" ; 10, 35, 33, 607, 213, "10:35:33.607213", "\023\245\073\110\179\158\226\064" ; 12, 10, 45, 725, 753, "12:10:45.725753", "\255\090\094\057\183\104\229\064" ; 17, 13, 10, 891, 783, "17:13:10.891783", "\133\128\124\137\220\068\238\064" ; 2, 5, 46, 811, 484, "02:05:46.811484", "\058\089\106\189\207\122\189\064" ; 13, 8, 50, 685, 910, "13:08:50.685910", "\064\135\249\242\085\028\231\064" ; 17, 17, 48, 119, 243, "17:17:48.119243", "\041\178\214\208\131\103\238\064" ; 2, 44, 20, 459, 82, "02:44:20.459082", "\024\240\050\195\058\066\195\064" ; 0, 24, 42, 385, 56, "00:24:42.385056", "\132\188\030\076\138\041\151\064" ; 10, 32, 30, 21, 245, "10:32:30.021245", "\135\254\009\174\192\135\226\064" ; 16, 24, 59, 389, 433, "16:24:59.389433", "\224\049\060\118\108\219\236\064" ; 21, 46, 10, 500, 119, "21:46:10.500119", "\210\199\124\000\040\034\243\064" ; 11, 28, 43, 415, 443, "11:28:43.415443", "\075\030\079\075\109\045\228\064" ; 14, 15, 19, 942, 56, "14:15:19.942056", "\224\159\082\037\254\014\233\064" ; 1, 45, 53, 556, 60, "01:45:53.556060", "\157\186\242\089\142\209\184\064" ; 0, 56, 24, 867, 671, "00:56:24.867671", "\096\145\095\063\188\113\170\064" ; 0, 51, 31, 532, 15, "00:51:31.532015", "\247\035\069\100\016\039\168\064" ; 10, 30, 30, 181, 302, "10:30:30.181302", "\022\218\057\205\197\120\226\064" ; 12, 31, 26, 89, 899, "12:31:26.089899", "\030\222\115\224\194\003\230\064" ; 14, 19, 7, 332, 673, "14:19:07.332673", "\233\216\065\165\106\043\233\064" ; 3, 33, 40, 970, 940, "03:33:40.970940", "\048\013\195\071\124\010\201\064" ; 6, 11, 23, 624, 654, "06:11:23.624654", "\084\197\084\250\231\194\213\064" ; 7, 25, 13, 384, 204, "07:25:13.384204", "\191\095\204\150\088\022\218\064" ; 13, 22, 36, 24, 328, "13:22:36.024328", "\140\131\075\199\128\131\231\064" ; 14, 39, 41, 876, 349, "14:39:41.876349", "\220\014\013\011\188\197\233\064" ; 1, 41, 2, 410, 243, "01:41:02.410243", "\106\108\175\005\105\174\183\064" ; 15, 46, 34, 219, 619, "15:46:34.219619", "\210\108\030\007\071\187\235\064" ; 12, 29, 44, 532, 503, "12:29:44.532503", "\065\187\067\010\017\247\229\064" ; 9, 26, 4, 828, 616, "09:26:04.828616", "\158\179\005\132\154\149\224\064" ; 23, 46, 11, 982, 961, "23:46:11.982961", "\068\080\053\186\063\228\244\064" ; 2, 9, 31, 157, 817, "02:09:31.157817", "\193\229\177\102\040\091\190\064" ; 12, 30, 56, 11, 111, "12:30:56.011111", "\180\116\005\091\000\000\230\064" ; 16, 26, 14, 228, 854, "16:26:14.228854", "\178\159\197\082\199\228\236\064" ; 21, 53, 30, 581, 24, "21:53:30.581024", "\099\210\223\075\169\061\243\064" ; 14, 8, 6, 613, 658, "14:08:06.613658", "\029\026\022\163\211\216\232\064" ; 14, 10, 24, 202, 539, "14:10:24.202539", "\165\017\051\123\006\234\232\064" ; 10, 18, 59, 884, 684, "10:18:59.884684", "\233\209\084\079\124\034\226\064" ; 2, 41, 28, 501, 556, "02:41:28.501556", "\143\172\252\050\064\236\194\064" ; 15, 14, 8, 423, 928, "15:14:08.423928", "\252\115\209\144\013\200\234\064" ; 17, 10, 48, 424, 625, "17:10:48.424625", "\002\043\135\150\013\051\238\064" ; 7, 15, 3, 150, 183, "07:15:03.150183", "\091\040\153\156\201\125\217\064" ; 12, 46, 26, 73, 842, "12:46:26.073842", "\226\229\233\092\066\116\230\064" ; 18, 5, 20, 956, 798, "18:05:20.956798", "\220\214\022\158\030\204\239\064" ; 12, 27, 52, 396, 932, "12:27:52.396932", "\216\188\170\179\012\233\229\064" ; 15, 37, 4, 309, 97, "15:37:04.309097", "\073\100\031\228\009\116\235\064" ; 23, 48, 14, 121, 97, "23:48:14.121097", "\106\104\003\240\225\235\244\064" ; 18, 36, 49, 212, 547, "18:36:49.212547", "\222\174\151\102\019\092\240\064" ; 23, 6, 44, 601, 433, "23:06:44.601433", "\155\053\120\159\073\080\244\064" ; 16, 31, 33, 998, 93, "16:31:33.998093", "\044\187\096\240\191\012\237\064" ; 22, 50, 3, 350, 146, "22:50:03.350146", "\046\177\050\154\181\017\244\064" ; 3, 30, 49, 269, 506, "03:30:49.269506", "\010\048\044\127\162\180\200\064" ; 13, 52, 39, 317, 858, "13:52:39.317858", "\089\138\228\043\234\100\232\064" ; 9, 50, 2, 244, 778, "09:50:02.244778", "\025\172\056\213\071\073\225\064" ; 9, 51, 47, 678, 113, "09:51:47.678113", "\192\008\026\179\117\086\225\064" ; 23, 27, 14, 216, 141, "23:27:14.216141", "\229\067\080\117\035\157\244\064" ; 17, 2, 54, 923, 602, "17:02:54.923602", "\017\200\037\142\221\247\237\064" ; 18, 49, 27, 932, 0, "18:49:27.932000", "\254\212\120\233\126\139\240\064" ; 3, 27, 46, 879, 606, "03:27:46.879606", "\175\237\237\150\112\089\200\064" ; 10, 16, 33, 599, 132, "10:16:33.599132", "\064\223\022\044\051\016\226\064" ; 4, 53, 47, 472, 58, "04:53:47.472058", "\245\193\050\054\222\054\209\064" ; 22, 28, 31, 144, 268, "22:28:31.144268", "\094\246\235\078\242\192\243\064" ; 9, 36, 14, 224, 239, "09:36:14.224239", "\112\068\247\044\199\225\224\064" ; 5, 18, 1, 746, 756, "05:18:01.746756", "\134\173\217\202\111\162\210\064" ; 6, 44, 55, 381, 59, "06:44:55.381059", "\183\073\069\099\216\185\215\064" ; 17, 14, 21, 78, 689, "17:14:21.078689", "\050\203\158\132\162\077\238\064" ; 20, 45, 2, 629, 313, "20:45:02.629313", "\031\130\170\017\234\060\242\064" ; 10, 18, 40, 937, 164, "10:18:40.937164", "\095\091\063\253\029\032\226\064" ; 14, 41, 30, 653, 510, "14:41:30.653510", "\179\205\141\233\084\211\233\064" ; 21, 42, 35, 470, 5, "21:42:35.470005", "\127\246\035\133\183\020\243\064" ; 15, 33, 33, 728, 872, "15:33:33.728872", "\095\095\235\082\183\089\235\064" ; 16, 3, 47, 767, 799, "16:03:47.767799", "\093\053\207\145\120\060\236\064" ; 2, 21, 16, 14, 747, "02:21:16.014747", "\091\205\058\227\001\142\192\064" ; 5, 47, 29, 147, 601, "05:47:29.147601", "\247\118\075\114\073\092\212\064" ; 13, 2, 54, 219, 755, "13:02:54.219755", "\068\163\059\008\199\239\230\064" ; 21, 2, 34, 452, 347, "21:02:34.452347", "\055\053\208\060\167\126\242\064" ; 2, 55, 7, 274, 766, "02:55:07.274766", "\006\068\136\043\163\133\196\064" ; 7, 48, 1, 535, 287, "07:48:01.535287", "\190\103\036\066\098\108\219\064" ; 18, 4, 1, 850, 703, "18:04:01.850703", "\115\127\245\056\059\194\239\064" ; 21, 49, 53, 266, 693, "21:49:53.266693", "\017\225\095\068\020\048\243\064" ; 18, 18, 12, 764, 605, "18:18:12.764605", "\213\115\210\059\076\022\240\064" ; 9, 46, 3, 797, 845, "09:46:03.797845", "\201\060\242\135\121\043\225\064" ; 6, 54, 56, 799, 810, "06:54:56.799810", "\065\072\022\048\051\080\216\064" ; 4, 9, 24, 762, 344, "04:09:24.762344", "\039\250\124\148\097\058\205\064" ; 23, 42, 23, 572, 694, "23:42:23.572694", "\010\047\193\041\249\213\244\064" ; 8, 45, 49, 820, 402, "08:45:49.820402", "\229\099\119\129\116\207\222\064" ; 11, 40, 30, 197, 269, "11:40:30.197269", "\240\019\007\080\198\133\228\064" ; 13, 31, 51, 161, 40, "13:31:51.161040", "\171\091\061\039\229\200\231\064" ; 19, 42, 52, 507, 728, "19:42:52.507728", "\052\101\167\031\200\083\241\064" ; 5, 58, 30, 669, 295, "05:58:30.669295", "\025\178\186\213\170\001\213\064" ; 5, 29, 30, 925, 731, "05:29:30.925731", "\121\060\045\063\187\078\211\064" ; 0, 15, 45, 619, 773, "00:15:45.619773", "\141\239\139\075\245\140\141\064" ; 11, 44, 56, 687, 748, "11:44:56.687748", "\252\023\008\002\022\167\228\064" ; 3, 17, 18, 962, 631, "03:17:18.962631", "\143\027\126\055\123\031\199\064" ; 6, 26, 58, 552, 27, "06:26:58.552027", "\224\013\105\084\163\172\214\064" ; 15, 1, 47, 372, 502, "15:01:47.372502", "\119\080\137\235\107\107\234\064" ; 10, 50, 31, 318, 680, "10:50:31.318680", "\060\102\160\050\234\014\227\064" ; 7, 45, 13, 526, 106, "07:45:13.526106", "\015\128\184\171\097\066\219\064" ; 15, 49, 3, 558, 810, "15:49:03.558810", "\085\130\197\225\241\205\235\064" ; 2, 9, 46, 798, 796, "02:09:46.798796", "\045\008\229\125\204\106\190\064" ; 2, 19, 56, 256, 143, "02:19:56.256143", "\012\056\075\201\032\102\192\064" ; 3, 50, 46, 232, 927, "03:50:46.232927", "\173\075\141\208\029\011\203\064" ; 18, 10, 21, 115, 808, "18:10:21.115808", "\147\250\178\180\163\241\239\064" ; 11, 35, 55, 732, 505, "11:35:55.732505", "\102\083\174\112\119\099\228\064" ; 2, 33, 9, 751, 208, "02:33:09.751208", "\063\112\149\039\224\242\193\064" ; 19, 52, 46, 965, 211, "19:52:46.965211", "\236\022\129\113\239\120\241\064" ; 4, 40, 9, 19, 612, "04:40:09.019612", "\167\176\082\065\065\106\208\064" ; 2, 26, 37, 301, 574, "02:26:37.301574", "\169\017\250\153\166\046\193\064" ; 15, 52, 59, 846, 43, "15:52:59.846043", "\000\197\200\018\123\235\235\064" ; 3, 41, 42, 270, 875, "03:41:42.270875", "\039\049\008\172\034\251\201\064" ; 9, 54, 45, 15, 529, "09:54:45.015529", "\100\172\054\127\160\108\225\064" ; 19, 37, 54, 442, 953, "19:37:54.442953", "\138\226\085\022\039\065\241\064" ; 6, 55, 32, 213, 402, "06:55:32.213402", "\186\220\096\168\013\089\216\064" ; 10, 35, 14, 739, 498, "10:35:14.739498", "\175\181\247\169\087\156\226\064" ; 15, 19, 24, 944, 650, "15:19:24.944650", "\006\163\146\058\158\239\234\064" ; 14, 48, 49, 551, 253, "14:48:49.551253", "\218\084\221\163\049\010\234\064" ; 4, 4, 46, 151, 814, "04:04:46.151814", "\138\034\164\110\019\175\204\064" ; 7, 41, 29, 752, 937, "07:41:29.752937", "\189\171\030\048\112\010\219\064" ; 10, 35, 44, 803, 696, "10:35:44.803696", "\126\172\224\183\025\160\226\064" ; 18, 1, 37, 477, 353, "18:01:37.477353", "\117\204\121\070\047\176\239\064" ; 1, 57, 43, 869, 396, "01:57:43.869396", "\070\123\188\144\222\151\187\064" ; 17, 35, 43, 990, 46, "17:35:43.990046", "\241\242\116\174\255\237\238\064" ; 6, 30, 55, 494, 256, "06:30:55.494256", "\246\234\227\161\223\231\214\064" ; 8, 45, 23, 299, 611, "08:45:23.299611", "\161\157\211\044\211\200\222\064" ; 7, 29, 21, 222, 626, "07:29:21.222626", "\080\031\129\063\078\084\218\064" ; 1, 33, 11, 424, 348, "01:33:11.424348", "\031\014\018\162\108\215\181\064" ; 8, 21, 57, 195, 121, "08:21:57.195121", "\113\202\220\124\076\105\221\064" ; 21, 46, 44, 519, 632, "21:46:44.519632", "\223\164\105\080\072\036\243\064" ; 0, 34, 31, 146, 950, "00:34:31.146950", "\076\200\007\061\075\046\160\064" ; 4, 37, 11, 70, 497, "04:37:11.070497", "\094\217\005\131\196\061\208\064" ; 22, 51, 24, 118, 510, "22:51:24.118510", "\228\189\106\229\193\022\244\064" ; 1, 45, 51, 424, 300, "01:45:51.424300", "\177\191\236\158\108\207\184\064" ; 5, 12, 39, 566, 810, "05:12:39.566810", "\067\115\157\070\228\081\210\064" ; 10, 38, 16, 49, 583, "10:38:16.049583", "\110\022\047\150\001\179\226\064" ; 3, 2, 2, 252, 218, "03:02:02.252218", "\187\238\173\072\032\085\197\064" ; 23, 15, 12, 329, 649, "23:15:12.329649", "\162\007\062\070\005\112\244\064" ; 19, 13, 46, 536, 289, "19:13:46.536289", "\067\198\163\148\168\230\240\064" ; 1, 40, 56, 881, 256, "01:40:56.881256", "\104\067\254\153\225\168\183\064" ; 20, 43, 0, 976, 739, "20:43:00.976739", "\219\018\185\160\079\053\242\064" ; 1, 19, 49, 852, 926, "01:19:49.852926", "\232\187\091\089\218\181\178\064" ; 14, 35, 1, 300, 200, "14:35:01.300200", "\201\007\061\155\169\162\233\064" ; 15, 24, 38, 25, 33, "15:24:38.025033", "\138\001\018\205\192\022\235\064" ; 16, 44, 8, 15, 246, "16:44:08.015246", "\237\045\229\124\000\107\237\064" ; 10, 35, 24, 477, 622, "10:35:24.477622", "\187\238\173\072\143\157\226\064" ; 16, 35, 53, 743, 584, "16:35:53.743584", "\059\172\112\203\055\045\237\064" ; 16, 59, 23, 80, 746, "16:59:23.080746", "\169\162\120\149\098\221\237\064" ; 7, 1, 34, 840, 91, "07:01:34.840091", "\171\010\013\196\181\179\216\064" ; 17, 42, 29, 554, 205, "17:42:29.554205", "\200\031\012\188\177\032\239\064" ; 8, 24, 55, 142, 839, "08:24:55.142839", "\102\048\070\036\201\149\221\064" ; 22, 45, 4, 904, 795, "22:45:04.904795", "\105\082\010\122\014\255\243\064" ; 19, 21, 19, 379, 13, "19:21:19.379013", "\124\239\111\016\246\002\241\064" ; 7, 31, 56, 377, 315, "07:31:56.377315", "\083\208\237\037\024\123\218\064" ; 19, 41, 41, 535, 997, "19:41:41.535997", "\028\151\113\147\088\079\241\064" ; 3, 10, 52, 602, 145, "03:10:52.602145", "\058\093\022\019\077\094\198\064" ; 16, 4, 35, 228, 187, "16:04:35.228187", "\204\210\078\077\103\066\236\064" ; 15, 27, 6, 607, 793, "15:27:06.607793", "\056\078\010\115\083\041\235\064" ; 1, 38, 17, 337, 726, "01:38:17.337726", "\003\013\054\117\086\009\183\064" ; 13, 2, 56, 274, 163, "13:02:56.274163", "\216\123\241\197\008\240\230\064" ; 20, 17, 31, 300, 649, "20:17:31.300649", "\105\083\117\207\180\213\241\064" ; 20, 55, 54, 859, 243, "20:55:54.859243", "\133\150\117\191\173\101\242\064" ; 11, 46, 14, 593, 76, "11:46:14.593076", "\001\133\122\250\210\176\228\064" ; 14, 28, 25, 85, 739, "14:28:25.085739", "\032\183\095\190\034\113\233\064" ; 8, 25, 6, 117, 427, "08:25:06.117427", "\042\137\236\131\135\152\221\064" ; 11, 4, 21, 507, 524, "11:04:21.507524", "\190\248\162\061\176\118\227\064" ; 6, 57, 3, 526, 83, "06:57:03.526083", "\255\007\088\171\225\111\216\064" ; 7, 6, 3, 449, 194, "07:06:03.449194", "\228\048\152\191\220\246\216\064" ; 3, 57, 14, 387, 192, "03:57:14.387192", "\163\232\129\143\049\205\203\064" ; 6, 56, 34, 29, 245, "06:56:34.029245", "\164\107\038\223\129\104\216\064" ; 19, 35, 32, 608, 455, "19:35:32.608455", "\097\079\059\188\073\056\241\064" ; 17, 22, 8, 798, 239, "17:22:08.798239", "\237\131\044\139\025\136\238\064" ; 6, 18, 10, 671, 22, "06:18:10.671022", "\057\066\006\242\170\040\214\064" ; 2, 47, 52, 251, 657, "02:47:52.251657", "\104\236\075\054\032\172\195\064" ; 21, 30, 32, 18, 588, "21:30:32.018588", "\065\238\034\076\128\231\242\064" ; 23, 23, 40, 728, 507, "23:23:40.728507", "\191\244\246\167\203\143\244\064" ; 21, 56, 1, 34, 333, "21:56:01.034333", "\131\194\160\140\016\071\243\064" ; 6, 48, 20, 830, 801, "06:48:20.830801", "\031\245\215\043\053\237\215\064" ; 23, 48, 40, 850, 423, "23:48:40.850423", "\205\037\085\155\141\237\244\064" ; 3, 48, 21, 241, 544, "03:48:21.241544", "\070\238\233\234\158\194\202\064" ; 20, 30, 57, 705, 435, "20:30:57.705435", "\231\053\118\073\027\008\242\064" ; 22, 25, 33, 338, 94, "22:25:33.338094", "\016\065\213\104\213\181\243\064" ; 10, 32, 7, 453, 250, "10:32:07.453250", "\221\036\006\129\238\132\226\064" ; 23, 49, 48, 389, 464, "23:49:48.389464", "\111\154\062\059\198\241\244\064" ; 19, 49, 26, 951, 591, "19:49:26.951591", "\003\124\183\057\111\108\241\064" ; 10, 23, 51, 710, 948, "10:23:51.710948", "\037\005\022\192\246\070\226\064" ; 6, 38, 16, 101, 995, "06:38:16.101995", "\086\009\022\135\006\086\215\064" ; 16, 51, 28, 914, 549, "16:51:28.914549", "\178\067\252\067\029\162\237\064" ; 8, 53, 20, 181, 204, "08:53:20.181204", "\122\169\216\152\011\064\223\064" ; 14, 28, 1, 292, 205, "14:28:01.292205", "\215\076\190\089\041\110\233\064" ; 3, 33, 14, 107, 583, "03:33:14.107583", "\077\157\071\197\013\253\200\064" ; 22, 15, 31, 446, 616, "22:15:31.446616", "\158\209\086\037\055\144\243\064" ; 14, 1, 33, 979, 455, "14:01:33.979455", "\029\003\178\087\191\167\232\064" ; 8, 40, 34, 881, 314, "08:40:34.881314", "\225\213\114\103\184\128\222\064" ; 10, 44, 33, 416, 835, "10:44:33.416835", "\154\090\182\086\045\226\226\064" ; 13, 21, 21, 714, 567, "13:21:21.714567", "\250\156\187\221\054\122\231\064" ; 2, 48, 45, 526, 10, "02:48:45.526010", "\175\177\075\084\195\198\195\064" ; 21, 6, 25, 161, 27, "21:06:25.161027", "\044\012\145\147\018\141\242\064" ; 23, 38, 1, 326, 360, "23:38:01.326360", "\108\067\197\056\149\197\244\064" ; 23, 4, 27, 772, 462, "23:04:27.772462", "\054\029\001\092\188\071\244\064" ; 7, 6, 20, 649, 26, "07:06:20.649026", "\017\089\164\137\041\251\216\064" ; 0, 34, 13, 135, 675, "00:34:13.135675", "\197\143\049\119\069\010\160\064" ; 13, 2, 13, 673, 832, "13:02:13.673832", "\096\032\008\144\181\234\230\064" ; 8, 34, 41, 715, 223, "08:34:41.715223", "\150\176\054\198\109\040\222\064" ; 10, 5, 14, 728, 575, "10:05:14.728575", "\182\132\124\080\087\187\225\064" ; 23, 16, 2, 451, 408, "23:16:02.451408", "\083\152\247\056\039\115\244\064" ; 2, 39, 11, 154, 464, "02:39:11.154464", "\053\242\121\197\147\167\194\064" ; 3, 31, 33, 326, 600, "03:31:33.326600", "\111\095\007\206\169\202\200\064" ; 20, 18, 45, 541, 247, "20:18:45.541247", "\065\157\242\168\088\218\241\064" ; 5, 33, 25, 774, 805, "05:33:25.774805", "\242\181\103\150\113\137\211\064" ; 21, 12, 15, 222, 353, "21:12:15.222353", "\242\004\194\142\243\162\242\064" ; 5, 24, 56, 22, 740, "05:24:56.022740", "\020\121\146\116\001\010\211\064" ; 15, 51, 45, 667, 580, "15:51:45.667580", "\111\187\208\092\053\226\235\064" ; 22, 2, 53, 216, 104, "22:02:53.216104", "\201\119\041\117\211\096\243\064" ; 2, 38, 4, 728, 292, "02:38:04.728292", "\248\024\172\056\093\134\194\064" ; 14, 13, 56, 554, 513, "14:13:56.554513", "\006\012\146\190\145\004\233\064" ; 20, 39, 2, 309, 130, "20:39:02.309130", "\131\076\050\242\100\038\242\064" ; 8, 42, 42, 977, 665, "08:42:42.977665", "\092\056\016\146\190\160\222\064" ; 21, 0, 24, 973, 909, "21:00:24.973909", "\132\154\033\149\143\118\242\064" ; 1, 4, 51, 187, 524, "01:04:51.187524", "\110\078\037\003\096\102\174\064" ; 2, 24, 34, 795, 59, "02:24:34.795059", "\178\073\126\196\101\241\192\064" ; 17, 53, 51, 367, 751, "17:53:51.367751", "\194\190\157\196\235\117\239\064" ; 15, 36, 14, 477, 703, "15:36:14.477703", "\070\205\087\073\207\109\235\064" ; 23, 36, 16, 970, 908, "23:36:16.970908", "\183\211\214\136\015\191\244\064" ; 20, 56, 49, 828, 606, "20:56:49.828606", "\116\093\248\065\029\105\242\064" ; 0, 12, 53, 216, 656, "00:12:53.216656", "\220\019\036\182\187\041\136\064" ; 21, 41, 54, 534, 171, "21:41:54.534171", "\248\227\246\139\040\018\243\064" ; 2, 14, 7, 324, 42, "02:14:07.324042", "\135\160\106\244\082\111\191\064" ; 9, 53, 36, 137, 417, "09:53:36.137417", "\030\086\184\101\004\100\225\064" ; 22, 24, 15, 813, 683, "22:24:15.813683", "\037\119\216\004\253\176\243\064" ; 14, 1, 31, 957, 103, "14:01:31.957103", "\125\120\150\160\126\167\232\064" ; 0, 53, 47, 131, 954, "00:53:47.131954", "\039\133\121\143\067\054\169\064" ; 5, 41, 58, 879, 888, "05:41:58.879888", "\009\194\021\080\184\009\212\064" ; 15, 28, 26, 492, 251, "15:28:26.492251", "\077\043\133\192\079\051\235\064" ; 22, 29, 7, 494, 467, "22:29:07.494467", "\160\058\086\233\055\195\243\064" ; 5, 9, 6, 147, 514, "05:09:06.147514", "\109\143\222\112\137\028\210\064" ; 17, 39, 14, 876, 143, "17:39:14.876143", "\115\011\093\009\092\008\239\064" ; 11, 34, 52, 690, 349, "11:34:52.690349", "\059\201\086\023\150\091\228\064" ; 4, 18, 24, 354, 581, "04:18:24.354581", "\100\003\233\098\045\072\206\064" ; 4, 5, 18, 88, 574, "04:05:18.088574", "\163\144\100\086\011\191\204\064" ; 5, 48, 23, 277, 625, "05:48:23.277625", "\227\165\155\196\209\105\212\064" ; 22, 51, 33, 997, 689, "22:51:33.997689", "\169\189\136\246\095\023\244\064" ; 7, 17, 57, 856, 93, "07:17:57.856093", "\085\075\058\202\118\169\217\064" ; 9, 38, 48, 577, 643, "09:38:48.577643", "\056\044\013\124\018\245\224\064" ; 1, 24, 53, 460, 972, "01:24:53.460972", "\095\208\066\002\118\229\179\064" ; 3, 41, 57, 231, 842, "03:41:57.231842", "\235\167\255\172\157\002\202\064" ; 23, 39, 28, 29, 434, "23:39:28.029434", "\054\201\143\120\000\203\244\064" ; 23, 28, 1, 351, 310, "23:28:01.351310", "\012\060\247\158\021\160\244\064" ; 1, 12, 38, 582, 665, "01:12:38.582665", "\134\143\136\041\149\006\177\064" ; 15, 31, 38, 731, 84, "15:31:38.731084", "\212\069\010\101\087\075\235\064" ; 22, 18, 11, 127, 347, "22:18:11.127347", "\003\002\157\009\050\154\243\064" ; 4, 10, 54, 26, 978, "04:10:54.026978", "\219\221\003\116\003\103\205\064" ; 2, 0, 24, 16, 127, "02:00:24.016127", "\149\041\230\032\004\056\188\064" ; 3, 23, 15, 751, 337, "03:23:15.751337", "\163\145\207\043\224\209\199\064" ; 21, 9, 18, 659, 532, "21:09:18.659532", "\043\109\113\141\234\151\242\064" ; 19, 32, 35, 198, 225, "19:32:35.198225", "\068\250\237\043\051\045\241\064" ; 21, 49, 8, 679, 747, "21:49:08.679747", "\233\099\062\224\074\045\243\064" ; 2, 24, 8, 991, 883, "02:24:08.991883", "\059\171\005\246\126\228\192\064" ; 17, 17, 7, 265, 769, "17:17:07.265769", "\105\253\045\129\104\098\238\064" ; 11, 27, 0, 768, 83, "11:27:00.768083", "\179\204\034\148\152\032\228\064" ; 19, 20, 55, 142, 922, "19:20:55.142922", "\063\148\104\073\114\001\241\064" ; 17, 48, 39, 514, 178, "17:48:39.514178", "\203\107\037\116\240\078\239\064" ; 8, 46, 48, 906, 570, "08:46:48.906570", "\098\045\062\005\058\222\222\064" ; 7, 11, 37, 803, 826, "07:11:37.803826", "\107\155\226\113\115\074\217\064" ; 2, 39, 40, 712, 602, "02:39:40.712602", "\136\214\138\054\091\182\194\064" ; 16, 33, 18, 48, 440, "16:33:18.048440", "\251\010\210\140\193\025\237\064" ; 23, 21, 2, 986, 173, "23:21:02.986173", "\243\086\093\199\239\133\244\064" ; 7, 19, 12, 703, 790, "07:19:12.703790", "\080\054\229\010\045\188\217\064" ; 4, 34, 2, 277, 986, "04:34:02.277986", "\175\202\133\202\145\014\208\064" ; 7, 20, 21, 700, 67, "07:20:21.700067", "\129\209\229\205\108\205\217\064" ; 20, 46, 5, 829, 108, "20:46:05.829108", "\013\192\006\068\221\064\242\064" ; 12, 58, 21, 953, 839, "12:58:21.953839", "\213\093\217\133\190\205\230\064" ; 6, 3, 36, 217, 794, "06:03:36.217794", "\209\062\086\240\013\078\213\064" ; 20, 36, 25, 117, 912, "20:36:25.117912", "\125\177\247\226\145\028\242\064" ; 0, 52, 9, 307, 893, "00:52:09.307893", "\085\187\038\164\157\114\168\064" ; 13, 55, 0, 349, 889, "13:55:00.349889", "\136\106\074\050\139\118\232\064" ; 16, 8, 35, 90, 270, "16:08:35.090270", "\057\233\125\227\098\096\236\064" ; 8, 45, 55, 84, 758, "08:45:55.084758", "\132\209\172\108\197\208\222\064" ; 9, 48, 14, 103, 296, "09:48:14.103296", "\186\105\051\078\195\059\225\064" ; 12, 54, 15, 362, 133, "12:54:15.362133", "\250\241\151\150\235\174\230\064" ; 0, 13, 53, 744, 997, "00:13:53.744997", "\242\180\252\192\245\013\138\064" ; 3, 48, 36, 40, 576, "03:48:36.040576", "\129\040\152\049\005\202\202\064" ; 8, 17, 23, 177, 282, "08:17:23.177282", "\011\154\150\088\203\036\221\064" ; 6, 43, 56, 204, 836, "06:43:56.204836", "\067\116\008\028\013\171\215\064" ; 12, 55, 28, 567, 602, "12:55:28.567602", "\101\171\203\041\018\184\230\064" ; 19, 54, 2, 91, 669, "19:54:02.091669", "\209\233\121\119\161\125\241\064" ; 20, 23, 58, 425, 34, "20:23:58.425034", "\155\115\240\204\230\237\241\064" ; 16, 52, 29, 125, 167, "16:52:29.125167", "\113\057\094\001\164\169\237\064" ; 17, 56, 15, 887, 10, "17:56:15.887010", "\168\203\098\098\252\135\239\064" ; 4, 40, 45, 970, 804, "04:40:45.970804", "\181\025\167\033\126\115\208\064" ; 2, 19, 25, 704, 366, "02:19:25.704366", "\053\067\170\040\218\086\192\064" ; 20, 23, 12, 505, 279, "20:23:12.505279", "\198\110\159\021\008\235\241\064" ; 15, 48, 39, 434, 802, "15:48:39.434802", "\072\226\229\233\237\202\235\064" ; 6, 58, 11, 130, 785, "06:58:11.130785", "\116\012\200\094\200\128\216\064" ; 12, 42, 34, 674, 317, "12:42:34.674317", "\196\062\001\148\085\087\230\064" ; 23, 29, 47, 860, 677, "23:29:47.860677", "\247\062\085\197\189\166\244\064" ; 10, 17, 28, 878, 723, "10:17:28.878723", "\103\178\127\030\028\023\226\064" ; 9, 13, 26, 705, 326, "09:13:26.705326", "\225\212\007\146\214\054\224\064" ; 0, 56, 12, 624, 160, "00:56:12.624160", "\241\070\230\145\063\089\170\064" ; 2, 8, 26, 978, 81, "02:08:26.978081", "\215\051\132\099\250\026\190\064" ; 21, 20, 58, 129, 451, "21:20:58.129451", "\055\054\059\018\162\195\242\064" ; 6, 16, 53, 275, 303, "06:16:53.275303", "\096\121\144\158\081\021\214\064" ; 10, 20, 7, 946, 21, "10:20:07.946021", "\011\213\205\069\254\042\226\064" ; 11, 11, 32, 264, 528, "11:11:32.264528", "\156\108\003\119\136\172\227\064" ; 2, 36, 30, 690, 175, "02:36:30.690175", "\194\134\167\087\088\087\194\064" ; 0, 46, 57, 58, 297, "00:46:57.058297", "\233\184\026\217\029\002\166\064" ; 10, 6, 35, 862, 910, "10:06:35.862910", "\173\110\245\156\123\197\225\064" ; 23, 41, 29, 361, 855, "23:41:29.361855", "\239\119\040\202\149\210\244\064" ; 22, 58, 54, 487, 517, "22:58:54.487517", "\051\160\222\204\231\050\244\064" ; 9, 30, 3, 347, 992, "09:30:03.347992", "\105\030\192\034\107\179\224\064" ; 2, 0, 28, 907, 432, "02:00:28.907432", "\088\171\118\077\232\060\188\064" ; 20, 52, 39, 180, 172, "20:52:39.180172", "\250\008\252\225\114\089\242\064" ; 17, 45, 54, 399, 870, "17:45:54.399870", "\149\043\188\203\076\058\239\064" ; 6, 35, 10, 3, 771, "06:35:10.003771", "\107\184\200\061\128\039\215\064" ; 23, 59, 9, 606, 209, "23:59:09.606209", "\089\053\008\179\217\020\245\064" ; 17, 27, 53, 619, 927, "17:27:53.619927", "\221\037\113\214\051\179\238\064" ; 13, 0, 22, 225, 575, "13:00:22.225575", "\249\015\233\055\199\220\230\064" ; 2, 27, 47, 909, 765, "02:27:47.909765", "\006\245\045\115\244\081\193\064" ; 5, 27, 12, 567, 139, "05:27:12.567139", "\082\096\001\076\036\044\211\064" ; 2, 57, 18, 519, 918, "02:57:18.519918", "\077\075\172\140\066\199\196\064" ; 17, 8, 33, 897, 733, "17:08:33.897733", "\113\142\058\186\060\034\238\064" ; 16, 1, 15, 94, 640, "16:01:15.094640", "\028\119\074\007\099\041\236\064" ; 0, 5, 43, 677, 503, "00:05:43.677503", "\018\191\098\013\215\122\117\064" ; 22, 57, 26, 354, 397, "22:57:26.354397", "\077\048\156\171\101\045\244\064" ; 22, 1, 33, 432, 465, "22:01:33.432465", "\123\107\096\235\214\091\243\064" ; 2, 35, 38, 782, 629, "02:35:38.782629", "\243\227\047\045\100\061\194\064" ; 4, 15, 9, 585, 152, "04:15:09.585152", "\152\191\066\230\202\230\205\064" ; 19, 22, 10, 856, 779, "19:22:10.856779", "\142\229\093\181\045\006\241\064" ; 9, 16, 29, 534, 446, "09:16:29.534446", "\111\127\046\026\177\077\224\064" ; 4, 15, 56, 957, 339, "04:15:56.957339", "\024\152\021\138\122\254\205\064" ; 3, 33, 44, 638, 336, "03:33:44.638336", "\238\121\254\180\081\012\201\064" ; 15, 11, 5, 804, 559, "15:11:05.804559", "\022\132\242\190\057\177\234\064" ; 0, 41, 13, 630, 605, "00:41:13.630605", "\100\151\168\222\066\083\163\064" ; 9, 7, 50, 680, 457, "09:07:50.680457", "\043\194\077\198\213\012\224\064" ; 5, 46, 39, 999, 598, "05:46:39.999598", "\201\227\105\249\255\079\212\064" ; 8, 22, 46, 439, 804, "08:22:46.439804", "\041\173\191\037\156\117\221\064" ; 2, 47, 31, 343, 123, "02:47:31.343123", "\193\087\116\235\171\161\195\064" ; 12, 50, 37, 20, 69, "12:50:37.020069", "\085\190\103\164\160\147\230\064" ; 19, 46, 21, 647, 326, "19:46:21.647326", "\253\129\114\091\218\096\241\064" ; 1, 1, 58, 473, 384, "01:01:58.473384", "\230\060\099\095\242\012\173\064" ; 10, 45, 18, 682, 599, "10:45:18.682599", "\169\219\217\215\213\231\226\064" ; 6, 45, 42, 126, 92, "06:45:42.126092", "\018\046\228\017\136\197\215\064" ; 5, 19, 47, 804, 340, "05:19:47.804340", "\183\122\078\122\243\188\210\064" ; 3, 44, 5, 480, 401, "03:44:05.480401", "\251\171\199\125\189\066\202\064" ; 23, 20, 9, 441, 8, "23:20:09.441008", "\149\103\094\014\151\130\244\064" ; 6, 58, 28, 679, 918, "06:58:28.679918", "\126\201\198\131\043\133\216\064" ; 22, 17, 9, 963, 788, "22:17:09.963788", "\069\247\172\107\095\150\243\064" ; 16, 12, 0, 248, 990, "16:12:00.248990", "\097\224\185\247\007\122\236\064" ; 22, 37, 0, 757, 744, "22:37:00.757744", "\044\044\184\031\204\224\243\064" ; 10, 26, 17, 468, 983, "10:26:17.468983", "\236\162\232\001\047\089\226\064" ; 9, 55, 14, 861, 456, "09:55:14.861456", "\094\044\012\145\091\112\225\064" ; 2, 34, 42, 266, 319, "02:34:42.266319", "\167\177\189\022\034\033\194\064" ; 17, 33, 54, 828, 627, "17:33:54.828627", "\051\197\028\132\090\224\238\064" ; 9, 12, 58, 565, 12, "09:12:58.565012", "\187\011\148\020\082\051\224\064" ; 16, 24, 7, 501, 252, "16:24:07.501252", "\097\162\065\010\240\212\236\064" ; 2, 27, 56, 156, 884, "02:27:56.156884", "\162\096\198\020\020\086\193\064" ; 1, 28, 41, 320, 49, "01:28:41.320049", "\030\052\187\238\081\201\180\064" ; 21, 36, 18, 478, 6, "21:36:18.478006", "\149\158\233\165\039\253\242\064" ; 7, 39, 44, 265, 128, "07:39:44.265128", "\080\110\219\247\016\240\218\064" ; 23, 17, 21, 12, 545, "23:17:21.012545", "\204\098\098\051\016\120\244\064" ; 19, 17, 12, 913, 512, "19:17:12.913512", "\072\194\190\157\142\243\240\064" ; 20, 41, 37, 106, 686, "20:41:37.106686", "\015\097\252\180\017\048\242\064" ; 7, 51, 15, 313, 455, "07:51:15.313455", "\113\143\165\015\212\156\219\064" ; 13, 57, 6, 794, 982, "13:57:06.794982", "\093\023\126\112\089\134\232\064" ; 22, 27, 38, 428, 716, "22:27:38.428716", "\244\078\005\220\166\189\243\064" ; 19, 6, 58, 943, 191, "19:06:58.943191", "\046\114\079\023\047\205\240\064" ; 10, 47, 53, 995, 437, "10:47:53.995437", "\008\178\158\218\063\251\226\064" ; 8, 25, 39, 85, 612, "08:25:39.085612", "\009\193\170\122\197\160\221\064" ; 16, 41, 37, 333, 208, "16:41:37.333208", "\216\210\163\169\042\088\237\064" ; 23, 16, 53, 910, 476, "23:16:53.910476", "\061\072\079\145\094\118\244\064" ; 18, 24, 35, 208, 156, "18:24:35.208156", "\199\098\155\084\051\046\240\064" ; 19, 33, 13, 123, 884, "19:33:13.123884", "\008\202\109\251\145\047\241\064" ; 4, 1, 47, 902, 991, "04:01:47.902991", "\203\134\053\149\243\085\204\064" ; 16, 51, 2, 834, 888, "16:51:02.834888", "\251\009\103\183\218\158\237\064" ; 9, 39, 8, 876, 849, "09:39:08.876849", "\080\162\037\015\156\247\224\064" ; 15, 24, 51, 339, 275, "15:24:51.339275", "\171\062\087\219\106\024\235\064" ; 10, 30, 49, 522, 70, "10:30:49.522070", "\007\037\204\180\048\123\226\064" ; 2, 57, 12, 61, 249, "02:57:12.061249", "\245\217\001\215\007\196\196\064" ; 23, 45, 47, 283, 563, "23:45:47.283563", "\053\091\121\137\180\226\244\064" ; 15, 2, 37, 525, 98, "15:02:37.525098", "\038\082\154\205\176\113\234\064" ; 17, 38, 38, 465, 690, "17:38:38.465690", "\002\183\238\230\206\003\239\064" ; 18, 44, 45, 769, 209, "18:44:45.769209", "\173\024\174\078\220\121\240\064" ; 22, 21, 17, 981, 150, "22:21:17.981150", "\168\087\202\178\223\165\243\064" ; 10, 27, 37, 250, 215, "10:27:37.250215", "\063\227\194\001\040\099\226\064" ; 23, 21, 23, 478, 796, "23:21:23.478796", "\151\254\037\169\055\135\244\064" ; 0, 9, 49, 616, 476, "00:09:49.616476", "\039\022\248\138\238\108\130\064" ; 0, 48, 43, 14, 819, "00:48:43.014819", "\184\032\091\150\007\214\166\064" ; 2, 56, 34, 892, 779, "02:56:34.892779", "\199\015\149\070\114\177\196\064" ; 17, 38, 53, 146, 746, "17:38:53.146746", "\218\170\036\178\164\005\239\064" ; 23, 52, 15, 240, 93, "23:52:15.240093", "\240\193\107\215\243\250\244\064" ; 21, 33, 31, 875, 759, "21:33:31.875759", "\131\222\027\003\190\242\242\064" ; 12, 44, 26, 493, 867, "12:44:26.493867", "\179\042\194\205\079\101\230\064" ; 14, 32, 20, 684, 423, "14:32:20.684423", "\052\016\203\230\149\142\233\064" ; 11, 8, 22, 703, 917, "11:08:22.703917", "\195\241\124\134\214\148\227\064" ; 4, 53, 52, 372, 13, "04:53:52.372013", "\044\157\015\207\023\056\209\064" ; 9, 14, 28, 304, 921, "09:14:28.304921", "\091\175\233\193\137\062\224\064" ; 16, 51, 19, 386, 277, "16:51:19.386277", "\070\149\097\092\236\160\237\064" ; 4, 37, 41, 937, 281, "04:37:41.937281", "\139\114\105\252\123\069\208\064" ; 6, 20, 27, 33, 548, "06:20:27.033548", "\182\130\166\037\194\074\214\064" ; 10, 19, 6, 870, 853, "10:19:06.870853", "\084\028\007\222\091\035\226\064" ; 2, 46, 26, 672, 294, "02:46:26.672294", "\166\211\186\013\086\129\195\064" ; 9, 25, 20, 941, 603, "09:25:20.941603", "\090\157\156\033\030\144\224\064" ; 23, 18, 26, 806, 863, "23:18:26.806863", "\085\045\233\232\044\124\244\064" ; 19, 1, 13, 639, 867, "19:01:13.639867", "\236\045\229\060\154\183\240\064" ; 9, 17, 1, 406, 74, "09:17:01.406074", "\185\230\142\254\172\081\224\064" ; 1, 40, 37, 559, 963, "01:40:37.559963", "\249\051\188\089\143\149\183\064" ; 16, 31, 27, 557, 490, "16:31:27.557490", "\187\068\245\214\241\011\237\064" ; 9, 55, 37, 485, 779, "09:55:37.485779", "\195\102\128\139\047\115\225\064" ; 5, 55, 13, 19, 282, "05:55:13.019282", "\218\145\234\059\065\208\212\064" ; 2, 33, 6, 949, 22, "02:33:06.949022", "\152\138\141\121\121\241\193\064" ; 13, 2, 15, 605, 195, "13:02:15.605195", "\151\231\193\093\243\234\230\064" ; 9, 45, 0, 590, 90, "09:45:00.590090", "\118\108\004\226\146\035\225\064" ; 21, 32, 22, 954, 206, "21:32:22.954206", "\186\130\109\068\111\238\242\064" ; 12, 52, 30, 534, 910, "12:52:30.534910", "\138\147\251\029\209\161\230\064" ; 5, 8, 5, 367, 777, "05:08:05.367777", "\206\138\168\137\087\013\210\064" ; 17, 48, 33, 351, 679, "17:48:33.351679", "\118\081\244\064\043\078\239\064" ; 4, 4, 17, 352, 763, "04:04:17.352763", "\031\134\086\039\173\160\204\064" ; 8, 47, 28, 934, 686, "08:47:28.934686", "\130\058\229\209\059\232\222\064" ; 20, 1, 7, 183, 575, "20:01:07.183575", "\214\086\236\239\050\152\241\064" ; 22, 54, 27, 430, 786, "22:54:27.430786", "\089\220\127\228\054\034\244\064" ; 5, 47, 26, 476, 476, "05:47:26.476476", "\085\049\149\126\158\091\212\064" ; 10, 30, 47, 769, 109, "10:30:47.769109", "\066\122\138\156\248\122\226\064" ; 9, 6, 33, 281, 656, "09:06:33.281656", "\151\113\083\003\041\003\224\064" ; 19, 9, 57, 951, 510, "19:09:57.951510", "\189\140\098\057\095\216\240\064" ; 14, 31, 56, 124, 379, "14:31:56.124379", "\042\171\233\250\131\139\233\064" ; 22, 57, 26, 612, 692, "22:57:26.612692", "\104\032\150\205\105\045\244\064" ; 17, 4, 37, 947, 410, "17:04:37.947410", "\189\198\046\081\190\004\238\064" ; 7, 2, 10, 201, 300, "07:02:10.201300", "\044\101\025\226\140\188\216\064" ; 21, 34, 33, 136, 286, "21:34:33.136286", "\142\058\058\046\146\246\242\064" ; 9, 48, 36, 402, 413, "09:48:36.402413", "\080\058\145\224\140\062\225\064" ; 4, 9, 27, 837, 832, "04:09:27.837832", "\197\055\020\062\235\059\205\064" ; 9, 39, 38, 126, 80, "09:39:38.126080", "\149\236\216\008\068\251\224\064" ; 13, 13, 18, 612, 633, "13:13:18.612633", "\111\133\176\154\211\061\231\064" ; 21, 57, 53, 694, 497, "21:57:53.694497", "\227\226\168\028\027\078\243\064" ; 10, 43, 6, 525, 178, "10:43:06.525178", "\211\023\066\206\080\215\226\064" ; 14, 3, 44, 981, 192, "14:03:44.981192", "\227\195\236\101\031\184\232\064" ; 11, 6, 23, 977, 605, "11:06:23.977605", "\237\071\138\072\255\133\227\064" ; 20, 30, 34, 933, 603, "20:30:34.933603", "\007\179\009\240\174\006\242\064" ; 13, 31, 28, 529, 766, "13:31:28.529766", "\145\211\215\243\016\198\231\064" ; 15, 4, 1, 891, 448, "15:04:01.891448", "\195\244\189\134\060\124\234\064" ; 8, 49, 48, 55, 975, "08:49:48.055975", "\153\042\024\149\003\011\223\064" ; 1, 15, 13, 157, 599, "01:15:13.157599", "\226\118\104\088\040\161\177\064" ; 19, 32, 14, 292, 327, "19:32:14.292327", "\140\019\095\173\228\043\241\064" ; 3, 26, 40, 173, 633, "03:26:40.173633", "\065\044\155\057\022\056\200\064" ; 16, 1, 57, 422, 992, "16:01:57.422992", "\207\132\038\137\173\046\236\064" ; 16, 5, 10, 98, 519, "16:05:10.098519", "\097\081\017\039\195\070\236\064" ; 22, 35, 4, 115, 290, "22:35:04.115290", "\185\083\058\216\129\217\243\064" ; 17, 11, 22, 675, 99, "17:11:22.675099", "\210\055\105\154\085\055\238\064" ; 2, 27, 6, 574, 357, "02:27:06.574357", "\158\185\135\132\073\061\193\064" ; 8, 17, 5, 202, 952, "08:17:05.202952", "\170\098\042\253\076\032\221\064" ; 21, 23, 47, 907, 492, "21:23:47.907492", "\215\084\022\133\062\206\242\064" ; 5, 17, 53, 721, 787, "05:17:53.721787", "\236\025\194\049\110\160\210\064" ; 21, 38, 4, 601, 298, "21:38:04.601298", "\210\166\234\158\201\003\243\064" ; 6, 44, 35, 535, 652, "06:44:35.535652", "\130\083\031\072\226\180\215\064" ; 17, 50, 1, 101, 313, "17:50:01.101313", "\181\194\244\061\035\089\239\064" ; 16, 20, 34, 839, 253, "16:20:34.839253", "\130\027\041\219\090\186\236\064" ; 10, 21, 18, 440, 710, "10:21:18.440710", "\161\219\075\026\206\051\226\064" ; 20, 43, 38, 30, 312, "20:43:38.030312", "\139\111\040\124\160\055\242\064" ; 5, 30, 0, 514, 911, "05:30:00.514911", "\086\068\077\244\032\086\211\064" ; 16, 59, 34, 738, 298, "16:59:34.738298", "\150\032\035\160\215\222\237\064" ; 21, 34, 7, 510, 454, "21:34:07.510454", "\065\208\209\042\248\244\242\064" ; 23, 31, 35, 722, 901, "23:31:35.722901", "\148\163\000\145\123\173\244\064" ; 19, 8, 53, 311, 32, "19:08:53.311032", "\192\176\252\249\084\212\240\064" ; 10, 15, 18, 581, 965, "10:15:18.581965", "\077\016\117\159\210\006\226\064" ; 3, 18, 3, 850, 743, "03:18:03.850743", "\039\137\037\229\236\053\199\064" ; 20, 44, 52, 752, 152, "20:44:52.752152", "\025\137\208\008\076\060\242\064" ; 5, 31, 21, 27, 416, "05:31:21.027416", "\216\009\047\193\065\106\211\064" ; 23, 13, 17, 404, 340, "23:13:17.404340", "\071\056\045\120\214\104\244\064" ; 11, 13, 56, 774, 892, "11:13:56.774892", "\189\078\234\203\152\190\227\064" ; 18, 14, 21, 496, 172, "18:14:21.496172", "\019\013\082\240\215\007\240\064" ; 4, 16, 46, 4, 181, "04:16:46.004181", "\034\197\000\137\000\023\206\064" ; 3, 5, 14, 415, 541, "03:05:14.415541", "\147\142\114\048\053\181\197\064" ; 13, 22, 15, 486, 452, "13:22:15.486452", "\226\200\003\145\239\128\231\064" ; 7, 18, 29, 636, 774, "07:18:29.636774", "\060\188\231\192\104\177\217\064" ; 16, 26, 34, 896, 312, "16:26:34.896312", "\224\128\150\174\092\231\236\064" ; 23, 50, 56, 328, 706, "23:50:56.328706", "\000\057\097\066\005\246\244\064" ; 10, 28, 30, 312, 498, "10:28:30.312498", "\066\206\251\255\201\105\226\064" ; 21, 4, 6, 93, 372, "21:04:06.093372", "\101\163\115\126\097\132\242\064" ; 3, 2, 58, 905, 766, "03:02:58.905766", "\234\233\035\240\115\113\197\064" ; 6, 9, 42, 293, 655, "06:09:42.293655", "\084\087\062\203\146\169\213\064" ; 10, 35, 10, 163, 776, "10:35:10.163776", "\124\042\167\061\197\155\226\064" ; 8, 10, 52, 754, 104, "08:10:52.754104", "\114\108\061\067\048\195\220\064" ; 7, 38, 21, 918, 183, "07:38:21.918183", "\048\161\130\195\122\219\218\064" ; 7, 22, 17, 196, 356, "07:22:17.196356", "\152\193\024\145\076\234\217\064" ; 19, 7, 7, 630, 273, "19:07:07.630273", "\041\036\153\021\186\205\240\064" ; 6, 42, 29, 349, 922, "06:42:29.349922", "\137\062\031\101\086\149\215\064" ; 16, 31, 30, 85, 370, "16:31:30.085370", "\194\221\089\187\066\012\237\064" ; 23, 13, 9, 905, 655, "23:13:09.905655", "\231\024\144\125\094\104\244\064" ; 18, 47, 32, 895, 807, "18:47:32.895807", "\137\184\057\085\078\132\240\064" ; 15, 30, 6, 601, 681, "15:30:06.601681", "\052\131\248\064\211\063\235\064" ; 8, 17, 33, 508, 764, "08:17:33.508764", "\089\225\150\143\096\039\221\064" ; 14, 13, 25, 995, 423, "14:13:25.995423", "\214\085\129\218\191\000\233\064" ; 16, 29, 44, 329, 836, "16:29:44.329836", "\033\058\004\142\010\255\236\064" ; 7, 57, 20, 700, 12, "07:57:20.700012", "\180\033\255\204\044\248\219\064" ; 0, 3, 48, 915, 309, "00:03:48.915309", "\128\151\025\054\074\157\108\064" ; 13, 35, 57, 43, 388, "13:35:57.043388", "\033\059\111\099\161\231\231\064" ; 19, 44, 48, 496, 905, "19:44:48.496905", "\067\168\082\243\007\091\241\064" ; 13, 10, 46, 589, 486, "13:10:46.589486", "\110\190\017\221\210\042\231\064" ; 11, 12, 18, 995, 597, "11:12:18.995597", "\096\061\238\219\095\178\227\064" ; 23, 23, 51, 519, 431, "23:23:51.519431", "\088\225\150\079\120\144\244\064" ; 18, 46, 3, 899, 983, "18:46:03.899983", "\000\147\084\102\190\126\240\064" ; 5, 31, 27, 871, 151, "05:31:27.871151", "\184\031\240\192\247\107\211\064" ; 12, 22, 26, 770, 194, "12:22:26.770194", "\050\227\109\165\088\192\229\064" ; 5, 50, 3, 437, 193, "05:50:03.437193", "\067\089\248\250\219\130\212\064" ; 2, 4, 50, 868, 40, "02:04:50.868040", "\159\147\222\055\222\066\189\064" ; 23, 10, 15, 582, 946, "23:10:15.582946", "\085\047\191\083\121\093\244\064" ; 11, 9, 54, 288, 993, "11:09:54.288993", "\121\063\110\063\073\160\227\064" ; 21, 23, 54, 866, 656, "21:23:54.866656", "\142\174\210\221\173\206\242\064" ; 1, 50, 3, 211, 177, "01:50:03.211177", "\171\036\178\015\054\203\185\064" ; 18, 41, 6, 38, 145, "18:41:06.038145", "\120\238\061\156\032\108\240\064" ; 10, 30, 17, 700, 835, "10:30:17.700835", "\156\133\061\109\054\119\226\064" ; 0, 50, 7, 95, 886, "00:50:07.095886", "\073\068\248\023\049\126\167\064" ; 8, 27, 7, 42, 887, "08:27:07.042887", "\155\029\169\190\194\182\221\064" ; 0, 56, 47, 393, 442, "00:56:47.393442", "\191\213\058\113\201\158\170\064" ; 13, 35, 21, 373, 994, "13:35:21.373994", "\221\067\194\247\043\227\231\064" ; 16, 57, 22, 363, 206, "16:57:22.363206", "\118\048\098\159\075\206\237\064" ; 17, 13, 30, 59, 829, "17:13:30.059829", "\203\129\030\234\065\071\238\064" ; 10, 33, 50, 878, 64, "10:33:50.878064", "\121\172\025\025\220\145\226\064" ; 13, 33, 16, 256, 788, "13:33:16.256788", "\192\119\155\055\136\211\231\064" ; 17, 41, 35, 208, 439, "17:41:35.208439", "\007\068\136\171\230\025\239\064" ; 17, 24, 10, 521, 337, "17:24:10.521337", "\166\238\202\174\080\151\238\064" ; 15, 59, 25, 506, 193, "15:59:25.506193", "\143\169\187\050\176\027\236\064" ; 9, 45, 11, 419, 380, "09:45:11.419380", "\019\155\143\107\237\036\225\064" ; 16, 46, 13, 567, 724, "16:46:13.567724", "\165\133\203\042\178\122\237\064" ; 14, 17, 37, 790, 253, "14:17:37.790253", "\210\168\192\073\057\032\233\064" ; 7, 0, 27, 379, 13, "07:00:27.379013", "\241\189\191\065\216\162\216\064" ; 14, 32, 5, 778, 111, "14:32:05.778111", "\053\010\073\230\184\140\233\064" ; 23, 57, 5, 139, 260, "23:57:05.139260", "\154\177\104\058\018\013\245\064" ; 23, 39, 46, 76, 141, "23:39:46.076141", "\014\160\223\055\033\204\244\064" ; 14, 27, 40, 611, 402, "14:27:40.611402", "\086\237\154\144\147\107\233\064" ; 14, 39, 23, 660, 155, "14:39:23.660155", "\234\096\253\031\117\195\233\064" ; 7, 53, 47, 651, 120, "07:53:47.651120", "\114\056\243\171\233\194\219\064" ; 20, 40, 39, 335, 812, "20:40:39.335812", "\090\103\124\095\117\044\242\064" ; 3, 38, 58, 95, 829, "03:38:58.095829", "\129\234\031\068\012\169\201\064" ; 7, 23, 18, 490, 216, "07:23:18.490216", "\255\237\178\095\159\249\217\064" ; 4, 49, 2, 31, 389, "04:49:02.031389", "\029\002\071\002\130\239\208\064" ; 20, 31, 55, 918, 139, "20:31:55.918139", "\035\133\178\176\190\011\242\064" ; 11, 20, 16, 169, 137, "11:20:16.169137", "\114\255\145\105\005\238\227\064" ; 16, 33, 10, 581, 343, "16:33:10.581343", "\152\162\092\154\210\024\237\064" ; 0, 9, 41, 609, 248, "00:09:41.609248", "\059\089\106\189\223\044\130\064" ; 4, 34, 7, 913, 267, "04:34:07.913267", "\097\110\247\114\250\015\208\064" ; 21, 59, 22, 783, 24, "21:59:22.783024", "\127\044\068\135\172\083\243\064" ; 15, 53, 40, 843, 966, "15:53:40.843966", "\030\252\196\001\155\240\235\064" ; 10, 47, 36, 175, 661, "10:47:36.175661", "\070\209\003\159\005\249\226\064" ; 9, 30, 50, 97, 746, "09:30:50.097746", "\042\056\188\032\067\185\224\064" ; 10, 54, 17, 662, 320, "10:54:17.662320", "\111\182\185\049\053\043\227\064" ; 6, 50, 31, 851, 871, "06:50:31.851871", "\090\241\013\133\246\013\216\064" ; 23, 33, 2, 985, 191, "23:33:02.985191", "\085\163\087\195\239\178\244\064" ; 13, 55, 21, 165, 740, "13:55:21.165740", "\245\248\189\077\037\121\232\064" ; 12, 8, 18, 903, 602, "12:08:18.903602", "\211\189\078\234\092\086\229\064" ; 1, 12, 53, 264, 661, "01:12:53.264661", "\135\195\210\192\067\021\177\064" ; 20, 57, 48, 740, 517, "20:57:48.740517", "\146\090\040\217\203\108\242\064" ; 19, 22, 42, 466, 896, "19:22:42.466896", "\170\240\103\120\039\008\241\064" ; 2, 0, 56, 893, 687, "02:00:56.893687", "\220\213\171\200\228\088\188\064" ; 10, 33, 20, 563, 254, "10:33:20.563254", "\171\064\045\006\018\142\226\064" ; 11, 44, 2, 470, 453, "11:44:02.470453", "\042\115\243\013\079\160\228\064" ; 1, 22, 21, 295, 742, "01:22:21.295742", "\014\106\191\181\075\077\179\064" ; 2, 20, 23, 616, 97, "02:20:23.616097", "\021\057\068\220\206\115\192\064" ; 19, 7, 2, 621, 498, "19:07:02.621498", "\008\227\167\241\105\205\240\064" ; 21, 59, 34, 93, 25, "21:59:34.093025", "\075\200\007\125\097\084\243\064" ; 11, 57, 41, 976, 30, "11:57:41.976030", "\062\068\163\059\191\006\229\064" ; 9, 3, 54, 454, 490, "09:03:54.454490", "\151\057\093\022\157\222\223\064" ; 0, 39, 7, 40, 662, "00:39:07.040662", "\097\080\166\209\020\086\162\064" ; 15, 49, 5, 238, 215, "15:49:05.238215", "\077\016\117\159\039\206\235\064" ; 16, 13, 50, 736, 810, "16:13:50.736810", "\171\144\242\147\215\135\236\064" ; 17, 4, 47, 358, 714, "17:04:47.358714", "\084\200\149\122\235\005\238\064" ; 19, 56, 38, 585, 476, "19:56:38.585476", "\010\021\028\094\105\135\241\064" ; 12, 47, 22, 363, 381, "12:47:22.363381", "\223\048\209\160\075\123\230\064" ; 17, 24, 43, 966, 838, "17:24:43.966838", "\209\062\086\240\126\155\238\064" ; 17, 26, 29, 667, 383, "17:26:29.667383", "\221\151\051\091\181\168\238\064" ; 0, 29, 27, 699, 667, "00:29:27.699667", "\093\140\129\117\204\158\155\064" ; 7, 1, 3, 945, 658, "07:01:03.945658", "\205\033\169\133\252\171\216\064" ; 15, 49, 53, 613, 461, "15:49:53.613461", "\140\246\120\161\051\212\235\064" ; 15, 9, 24, 428, 672, "15:09:24.428672", "\151\087\174\183\141\164\234\064" ; 19, 17, 38, 315, 856, "19:17:38.315856", "\100\005\191\013\037\245\240\064" ; 12, 5, 32, 405, 244, "12:05:32.405244", "\221\067\194\247\140\065\229\064" ; 4, 29, 25, 207, 314, "04:29:25.207314", "\001\225\067\137\154\146\207\064" ; 0, 13, 2, 154, 923, "00:13:02.154923", "\047\019\069\072\061\113\136\064" ; 2, 47, 8, 784, 447, "02:47:08.784447", "\057\097\194\104\100\150\195\064" ; 6, 3, 7, 764, 722, "06:03:07.764722", "\034\139\052\241\240\070\213\064" ; 5, 26, 53, 29, 563, "05:26:53.029563", "\139\053\092\228\065\039\211\064" ; 11, 29, 6, 798, 86, "11:29:06.798086", "\173\166\235\137\089\048\228\064" ; 7, 7, 11, 809, 664, "07:07:11.809664", "\048\244\136\209\243\007\217\064" ; 23, 1, 27, 673, 457, "23:01:27.673457", "\228\216\122\198\122\060\244\064" ; 8, 47, 31, 111, 548, "08:47:31.111548", "\252\056\154\035\199\232\222\064" ; 0, 36, 53, 738, 828, "00:36:53.738828", "\189\226\169\071\122\075\161\064" ; 21, 24, 51, 158, 357, "21:24:51.158357", "\129\089\161\136\050\210\242\064" ; 13, 38, 58, 965, 814, "13:38:58.965814", "\000\195\242\231\094\254\231\064" ; 19, 34, 47, 430, 271, "19:34:47.430271", "\022\216\099\226\118\053\241\064" ; 6, 22, 57, 451, 954, "06:22:57.451954", "\083\120\208\236\092\112\214\064" ; 1, 37, 53, 65, 974, "01:37:53.065974", "\098\012\172\227\016\241\182\064" ; 22, 23, 33, 317, 285, "22:23:33.317285", "\168\111\153\019\085\174\243\064" ; 2, 4, 43, 244, 506, "02:04:43.244506", "\173\249\241\151\062\059\189\064" ; 20, 36, 53, 232, 64, "20:36:53.232064", "\170\189\136\182\083\030\242\064" ; 23, 4, 14, 82, 537, "23:04:14.082537", "\059\081\018\082\225\070\244\064" ; 10, 26, 43, 778, 737, "10:26:43.778737", "\102\219\105\235\120\092\226\064" ; 3, 4, 27, 795, 695, "03:04:27.795695", "\076\113\085\217\229\157\197\064" ; 19, 8, 3, 667, 671, "19:08:03.667671", "\088\201\199\174\058\209\240\064" ; 13, 14, 43, 234, 982, "13:14:43.234982", "\164\248\248\132\103\072\231\064" ; 5, 10, 14, 718, 987, "05:10:14.718987", "\208\012\226\003\174\045\210\064" ; 21, 48, 9, 384, 269, "21:48:09.384269", "\062\064\247\037\150\041\243\064" ; 14, 56, 8, 785, 238, "14:56:08.785238", "\051\113\171\032\025\065\234\064" ; 7, 18, 38, 480, 395, "07:18:38.480395", "\138\171\202\190\158\179\217\064" ; 7, 35, 5, 167, 446, "07:35:05.167446", "\118\109\111\183\074\170\218\064" ; 10, 43, 40, 200, 165, "10:43:40.200165", "\025\110\192\103\134\219\226\064" ; 9, 10, 43, 105, 530, "09:10:43.105530", "\088\115\128\096\099\034\224\064" ; 17, 12, 48, 31, 444, "17:12:48.031444", "\245\216\150\001\001\066\238\064" ; 9, 39, 50, 684, 622, "09:39:50.684622", "\132\101\108\232\213\252\224\064" ; 17, 34, 47, 897, 262, "17:34:47.897262", "\062\204\094\182\252\230\238\064" ; 23, 17, 20, 771, 554, "23:17:20.771554", "\209\001\073\088\012\120\244\064" ; 19, 10, 33, 621, 367, "19:10:33.621367", "\253\133\030\241\153\218\240\064" ; 5, 37, 55, 493, 232, "05:37:55.493232", "\085\243\028\145\223\204\211\064" ; 13, 21, 12, 198, 487, "13:21:12.198487", "\181\104\001\090\006\121\231\064" ; 23, 47, 44, 849, 461, "23:47:44.849461", "\228\106\100\151\013\234\244\064" ; 0, 59, 7, 225, 278, "00:59:07.225278", "\004\085\163\087\115\182\171\064" ; 17, 3, 52, 447, 677, "17:03:52.447677", "\070\183\094\083\014\255\237\064" ; 8, 50, 19, 367, 241, "08:50:19.367241", "\048\101\224\128\215\018\223\064" ; 9, 21, 45, 133, 476, "09:21:45.133476", "\218\117\111\069\036\117\224\064" ; 9, 17, 14, 846, 529, "09:17:14.846529", "\067\252\195\022\091\083\224\064" ; 14, 8, 4, 974, 350, "14:08:04.974350", "\028\013\224\045\159\216\232\064" ; 13, 45, 42, 365, 855, "13:45:42.365855", "\130\139\021\181\203\048\232\064" ; 21, 53, 11, 55, 651, "21:53:11.055651", "\143\077\242\227\112\060\243\064" ; 16, 56, 53, 359, 440, "16:56:53.359440", "\156\080\136\128\171\202\237\064" ; 4, 3, 19, 852, 805, "04:03:19.852805", "\111\216\182\040\237\131\204\064" ; 12, 22, 58, 489, 684, "12:22:58.489684", "\172\199\125\171\079\196\229\064" ; 7, 36, 1, 194, 191, "07:36:01.194191", "\139\022\160\109\076\184\218\064" ; 10, 19, 0, 57, 954, "10:19:00.057954", "\214\088\194\218\129\034\226\064" ; 20, 56, 47, 36, 187, "20:56:47.036187", "\216\209\056\148\240\104\242\064" ; 19, 5, 0, 537, 412, "19:05:00.537412", "\071\083\061\153\200\197\240\064" ; 17, 4, 7, 493, 142, "17:04:07.493142", "\073\187\209\199\239\000\238\064" ; 13, 4, 42, 619, 967, "13:04:42.619967", "\179\008\197\214\083\253\230\064" ; 3, 27, 57, 622, 534, "03:27:57.622534", "\083\177\049\175\207\094\200\064" ; 14, 58, 20, 684, 874, "14:58:20.684874", "\252\224\124\234\149\081\234\064" ; 0, 36, 29, 28, 847, "00:36:29.028847", "\044\179\008\197\014\026\161\064" ; 0, 3, 49, 428, 619, "00:03:49.428619", "\055\110\049\063\183\173\108\064" ; 14, 34, 21, 504, 477, "14:34:21.504477", "\019\243\172\036\176\157\233\064" ; 19, 35, 45, 893, 499, "19:35:45.893499", "\128\155\197\075\030\057\241\064" ; 10, 27, 31, 312, 378, "10:27:31.312378", "\191\037\000\255\105\098\226\064" ; 3, 57, 32, 509, 876, "03:57:32.509876", "\130\228\157\067\065\214\203\064" ; 17, 9, 46, 238, 740, "17:09:46.238740", "\136\017\194\163\071\043\238\064" ; 5, 42, 36, 850, 569, "05:42:36.850569", "\127\245\184\111\054\019\212\064" ; 11, 25, 35, 353, 111, "11:25:35.353111", "\156\112\175\076\235\021\228\064" ; 21, 13, 15, 656, 267, "21:13:15.656267", "\103\211\017\128\186\166\242\064" ; 18, 53, 16, 836, 825, "18:53:16.836825", "\119\156\162\099\205\153\240\064" ; 20, 34, 55, 794, 975, "20:34:55.794975", "\162\180\055\184\252\022\242\064" ; 17, 9, 45, 595, 937, "17:09:45.595937", "\175\120\234\017\051\043\238\064" ; 2, 19, 54, 567, 268, "02:19:54.567268", "\008\226\060\156\072\101\192\064" ; 8, 8, 11, 808, 444, "08:08:11.808444", "\042\231\139\189\243\154\220\064" ; 18, 11, 2, 137, 500, "18:11:02.137500", "\103\102\102\102\196\246\239\064" ; 3, 21, 59, 742, 472, "03:21:59.742472", "\025\143\082\009\223\171\199\064" ; 8, 16, 28, 460, 734, "08:16:28.460734", "\138\117\170\124\029\023\221\064" ; 1, 44, 45, 735, 280, "01:44:45.735280", "\103\097\079\059\188\141\184\064" ; 23, 30, 58, 68, 458, "23:30:58.068458", "\114\106\103\024\033\171\244\064" ; 9, 18, 45, 21, 400, "09:18:45.021400", "\132\013\079\175\160\094\224\064" ; 21, 13, 10, 870, 563, "21:13:10.870563", "\225\119\211\237\109\166\242\064" ; 14, 26, 17, 614, 552, "14:26:17.614552", "\182\244\104\170\051\097\233\064" ; 0, 16, 51, 133, 582, "00:16:51.133582", "\173\138\112\147\017\153\143\064" ; 10, 19, 24, 167, 214, "10:19:24.167214", "\174\044\209\089\133\037\226\064" ; 15, 2, 3, 389, 111, "15:02:03.389111", "\113\233\152\115\108\109\234\064" ; 6, 15, 10, 980, 260, "06:15:10.980260", "\101\112\148\188\190\251\213\064" ; 1, 17, 15, 630, 260, "01:17:15.630260", "\250\039\184\088\161\027\178\064" ; 23, 19, 44, 873, 731, "23:19:44.873731", "\104\091\205\250\013\129\244\064" ; 7, 3, 1, 864, 953, "07:03:01.864953", "\229\211\099\091\119\201\216\064" ; 4, 41, 33, 385, 915, "04:41:33.385915", "\002\212\212\178\088\127\208\064" ; 10, 11, 4, 106, 209, "10:11:04.106209", "\177\106\016\102\003\231\225\064" ; 14, 40, 46, 536, 544, "14:40:46.536544", "\156\082\094\043\209\205\233\064" ; 10, 29, 4, 290, 808, "10:29:04.290808", "\045\148\076\078\009\110\226\064" ; 18, 28, 5, 213, 757, "18:28:05.213757", "\197\117\140\107\083\059\240\064" ; 0, 48, 7, 960, 261, "00:48:07.960261", "\064\109\084\167\235\143\166\064" ; 5, 53, 51, 949, 659, "05:53:51.949659", "\215\138\054\199\252\187\212\064" ; 1, 55, 19, 671, 287, "01:55:19.671287", "\059\255\118\217\171\007\187\064" ; 15, 18, 34, 561, 662, "15:18:34.561662", "\045\150\034\249\081\233\234\064" ; 7, 46, 57, 277, 647, "07:46:57.277647", "\053\236\247\196\081\092\219\064" ; 2, 54, 42, 988, 841, "02:54:42.988841", "\248\133\087\146\126\121\196\064" ; 1, 18, 13, 472, 732, "01:18:13.472732", "\198\223\246\004\121\085\178\064" ; 9, 51, 8, 44, 423, "09:51:08.044423", "\134\200\233\107\129\081\225\064" ; 16, 6, 2, 220, 136, "16:06:02.220136", "\022\167\090\011\071\077\236\064" ; 15, 57, 17, 867, 950, "15:57:17.867950", "\018\020\063\198\187\011\236\064" ; 3, 55, 4, 373, 201, "03:55:04.373201", "\235\228\012\197\047\140\203\064" ; 9, 56, 17, 36, 101, "09:56:17.036101", "\203\072\189\039\033\120\225\064" ; 1, 25, 5, 911, 373, "01:25:05.911373", "\117\173\189\079\233\241\179\064" ; 19, 13, 7, 314, 585, "19:13:07.314585", "\237\071\138\008\053\228\240\064" ; 18, 32, 50, 356, 778, "18:32:50.356778", "\031\217\092\181\037\077\240\064" ; 23, 52, 9, 779, 798, "23:52:09.779798", "\183\119\013\122\156\250\244\064" ; 13, 4, 21, 326, 923, "13:04:21.326923", "\042\057\039\118\170\250\230\064" ; 20, 11, 28, 291, 881, "20:11:28.291881", "\085\105\139\171\004\191\241\064" ; 2, 53, 43, 624, 679, "02:53:43.624679", "\192\065\123\245\207\091\196\064" ; 6, 32, 12, 510, 14, "06:32:12.510014", "\160\194\017\164\032\251\214\064" ; 10, 49, 15, 356, 382, "10:49:15.356382", "\092\057\123\103\107\005\227\064" ; 14, 59, 31, 982, 843, "14:59:31.982843", "\196\041\115\115\127\090\234\064" ; 16, 32, 5, 723, 933, "16:32:05.723933", "\240\137\117\042\183\016\237\064" ; 19, 57, 47, 205, 713, "19:57:47.205713", "\246\182\153\074\179\139\241\064" ; 18, 8, 12, 714, 80, "18:08:12.714080", "\215\076\190\217\150\225\239\064" ; 9, 37, 22, 83, 942, "09:37:22.083942", "\024\034\167\175\066\234\224\064" ; 18, 48, 2, 570, 753, "18:48:02.570753", "\210\229\205\033\041\134\240\064" ; 12, 58, 33, 652, 815, "12:58:33.652815", "\107\072\220\227\052\207\230\064" ; 14, 55, 34, 275, 418, "14:55:34.275418", "\216\104\057\208\200\060\234\064" ; 11, 40, 34, 775, 463, "11:40:34.775463", "\008\200\151\208\088\134\228\064" ; 8, 20, 15, 118, 581, "08:20:15.118581", "\059\195\212\150\199\079\221\064" ; 23, 13, 56, 795, 951, "23:13:56.795951", "\163\029\055\188\076\107\244\064" ; 3, 26, 1, 249, 93, "03:26:01.249093", "\085\136\071\226\159\036\200\064" ; 16, 56, 5, 569, 836, "16:56:05.569836", "\003\181\024\060\178\196\237\064" ; 11, 7, 48, 845, 566, "11:07:48.845566", "\148\109\224\014\155\144\227\064" ; 21, 42, 26, 610, 741, "21:42:26.610741", "\213\090\152\197\041\020\243\064" ; 20, 42, 24, 940, 446, "20:42:24.940446", "\219\026\017\012\015\051\242\064" ; 5, 3, 0, 870, 748, "05:03:00.870748", "\195\209\085\186\055\193\209\064" ; 4, 34, 52, 851, 201, "04:34:52.851201", "\084\194\019\122\054\027\208\064" ; 14, 3, 36, 288, 175, "14:03:36.288175", "\017\199\186\056\009\183\232\064" ; 3, 31, 41, 802, 547, "03:31:41.802547", "\064\047\220\185\230\206\200\064" ; 17, 21, 19, 611, 473, "17:21:19.611473", "\044\211\047\145\243\129\238\064" ; 17, 44, 59, 738, 743, "17:44:59.738743", "\036\092\200\163\119\051\239\064" ; 9, 41, 37, 833, 787, "09:41:37.833787", "\026\019\098\174\058\010\225\064" ; 12, 36, 11, 167, 665, "12:36:11.167665", "\118\253\130\093\101\039\230\064" ; 21, 51, 44, 463, 933, "21:51:44.463933", "\105\002\069\108\007\055\243\064" ; 22, 57, 41, 350, 601, "22:57:41.350601", "\080\203\015\156\085\046\244\064" ; 13, 26, 49, 176, 354, "13:26:49.176354", "\209\036\177\164\037\163\231\064" ; 8, 18, 23, 5, 617, "08:18:23.005617", "\212\103\007\092\192\051\221\064" ; 14, 33, 24, 236, 39, "14:33:24.236039", "\050\169\161\141\135\150\233\064" ; 19, 15, 5, 58, 855, "19:15:05.058855", "\196\240\017\241\144\235\240\064" ; 23, 0, 17, 126, 571, "23:00:17.126571", "\026\080\111\006\018\056\244\064" ; 19, 49, 23, 941, 219, "19:49:23.941219", "\118\167\059\015\063\108\241\064" ; 14, 4, 13, 508, 404, "14:04:13.508404", "\037\119\216\068\176\187\232\064" ; 23, 30, 7, 493, 632, "23:30:07.493632", "\004\171\234\229\247\167\244\064" ; 15, 2, 54, 770, 159, "15:02:54.770159", "\183\124\036\165\216\115\234\064" ; 14, 57, 36, 277, 762, "14:57:36.277762", "\067\034\109\227\008\076\234\064" ; 9, 15, 2, 560, 366, "09:15:02.560366", "\121\173\132\238\209\066\224\064" ; 13, 10, 31, 319, 278, "13:10:31.319278", "\011\127\134\055\234\040\231\064" ; 7, 58, 45, 792, 593, "07:58:45.792593", "\131\253\215\185\114\013\220\064" ; 4, 55, 32, 725, 766, "04:55:32.725766", "\163\060\243\114\046\081\209\064" ; 8, 27, 18, 689, 76, "08:27:18.689076", "\029\057\210\025\172\185\221\064" ; 9, 52, 48, 662, 776, "09:52:48.662776", "\146\003\118\053\021\094\225\064" ; 12, 33, 14, 93, 548, "12:33:14.093548", "\020\096\088\254\066\017\230\064" ; 14, 37, 38, 221, 59, "14:37:38.221059", "\239\082\234\018\071\182\233\064" ; 11, 8, 24, 377, 344, "11:08:24.377344", "\107\185\051\019\012\149\227\064" ; 14, 54, 28, 157, 325, "14:54:28.157325", "\059\112\206\008\133\052\234\064" ; 18, 46, 19, 323, 394, "18:46:19.323394", "\220\047\159\044\181\127\240\064" ; 4, 22, 6, 148, 619, "04:22:06.148619", "\072\136\242\005\019\183\206\064" ; 1, 6, 29, 303, 380, "01:06:29.303380", "\133\148\159\084\155\042\175\064" ; 20, 45, 39, 957, 478, "20:45:39.957478", "\138\115\212\081\063\063\242\064" ; 12, 49, 5, 559, 610, "12:49:05.559610", "\017\059\083\232\049\136\230\064" ; 19, 7, 21, 797, 688, "19:07:21.797688", "\007\126\084\195\156\206\240\064" ; 23, 9, 58, 575, 350, "23:09:58.575350", "\156\051\162\052\105\092\244\064" ; 23, 2, 9, 19, 658, "23:02:09.019658", "\050\232\132\080\016\063\244\064" ; 3, 33, 42, 880, 161, "03:33:42.880161", "\027\155\029\169\112\011\201\064" ; 15, 17, 11, 422, 571, "15:17:11.422571", "\039\158\179\133\237\222\234\064" ; 21, 46, 28, 236, 549, "21:46:28.236549", "\175\154\231\200\067\035\243\064" ; 0, 32, 13, 853, 8, "00:32:13.853008", "\232\220\237\122\105\055\158\064" ; 22, 58, 18, 987, 908, "22:58:18.987908", "\119\158\120\206\175\048\244\064" ; 13, 24, 45, 751, 630, "13:24:45.751630", "\150\091\090\013\184\147\231\064" ; 2, 37, 51, 151, 660, "02:37:51.151660", "\014\074\152\105\147\127\194\064" ; 5, 58, 10, 802, 345, "05:58:10.802345", "\199\215\158\089\179\252\212\064" ; 11, 56, 41, 872, 481, "11:56:41.872481", "\045\070\093\235\059\255\228\064" ; 19, 47, 9, 340, 874, "19:47:09.340874", "\161\075\056\116\213\099\241\064" ; 3, 14, 3, 807, 543, "03:14:03.807543", "\143\171\145\093\231\189\198\064" ; 21, 27, 26, 702, 761, "21:27:26.702761", "\127\081\130\062\235\219\242\064" ; 3, 30, 33, 516, 613, "03:30:33.516613", "\216\241\095\032\194\172\200\064" ; 0, 42, 4, 698, 893, "00:42:04.698893", "\206\164\077\213\101\185\163\064" ; 18, 35, 55, 284, 134, "18:35:55.284134", "\219\023\208\139\180\088\240\064" ; 15, 46, 58, 987, 85, "15:46:58.987085", "\044\072\051\150\095\190\235\064" ; 3, 24, 51, 360, 896, "03:24:51.360896", "\161\018\215\049\174\001\200\064" ; 15, 27, 52, 430, 990, "15:27:52.430990", "\093\138\171\202\013\047\235\064" ; 0, 26, 47, 415, 303, "00:26:47.415303", "\185\139\048\069\169\029\153\064" ; 23, 18, 54, 667, 250, "23:18:54.667250", "\004\086\014\173\234\125\244\064" ; 7, 15, 58, 727, 686, "07:15:58.727686", "\240\076\104\146\174\139\217\064" ; 3, 53, 26, 464, 712, "03:53:26.464712", "\007\205\174\123\059\091\203\064" ; 2, 53, 41, 852, 713, "02:53:41.852713", "\240\023\179\037\237\090\196\064" ; 17, 23, 59, 440, 932, "17:23:59.440932", "\249\108\029\028\238\149\238\064" ; 10, 57, 48, 588, 499, "10:57:48.588499", "\216\218\251\212\146\069\227\064" ; 20, 49, 27, 728, 827, "20:49:27.728827", "\023\128\070\169\123\077\242\064" ; 14, 8, 39, 440, 847, "14:08:39.440847", "\242\042\107\027\238\220\232\064" ; 22, 35, 31, 215, 162, "22:35:31.215162", "\149\181\077\113\051\219\243\064" ; 1, 0, 27, 285, 940, "01:00:27.285940", "\060\073\186\102\146\086\172\064" ; 11, 22, 4, 993, 755, "11:22:04.993755", "\040\073\215\204\159\251\227\064" ; 0, 8, 22, 496, 91, "00:08:22.496091", "\112\205\029\253\239\103\127\064" ; 13, 29, 11, 34, 382, "13:29:11.034382", "\178\071\168\025\225\180\231\064" ; 12, 44, 42, 220, 151, "12:44:42.220151", "\038\028\122\011\071\103\230\064" ; 5, 25, 3, 685, 985, "05:25:03.685985", "\035\161\045\231\235\011\211\064" ; 0, 29, 43, 113, 939, "00:29:43.113939", "\245\218\108\172\116\220\155\064" ; 23, 52, 10, 420, 483, "23:52:10.420483", "\216\097\076\186\166\250\244\064" ; 10, 37, 44, 718, 903, "10:37:44.718903", "\064\221\064\001\023\175\226\064" ; 10, 46, 23, 486, 70, "10:46:23.486070", "\050\172\226\141\239\239\226\064" ; 9, 28, 22, 987, 766, "09:28:22.987766", "\067\113\199\155\223\166\224\064" ; 19, 32, 15, 383, 911, "19:32:15.383911", "\089\220\127\036\246\043\241\064" ; 2, 23, 8, 943, 25, "02:23:08.943025", "\039\015\011\181\120\198\192\064" ; 10, 15, 52, 14, 292, "10:15:52.014292", "\019\127\020\117\000\011\226\064" ; 13, 30, 53, 581, 426, "13:30:53.581426", "\225\178\010\155\178\193\231\064" ; 17, 51, 14, 519, 927, "17:51:14.519927", "\170\242\061\163\080\098\239\064" ; 20, 27, 3, 482, 787, "20:27:03.482787", "\127\220\126\185\119\249\241\064" ; 12, 49, 32, 473, 880, "12:49:32.473880", "\199\099\006\042\143\139\230\064" ; 7, 10, 29, 855, 374, "07:10:29.855374", "\246\150\114\190\118\057\217\064" ; 22, 18, 0, 636, 434, "22:18:00.636434", "\001\107\213\046\138\153\243\064" ; 20, 0, 44, 77, 112, "20:00:44.077112", "\226\202\217\059\193\150\241\064" ; 5, 14, 14, 470, 664, "05:14:14.470664", "\218\229\091\031\158\105\210\064" ; 12, 35, 10, 429, 410, "12:35:10.429410", "\082\010\186\189\205\031\230\064" ; 9, 3, 19, 524, 667, "09:03:19.524667", "\147\229\036\148\225\213\223\064" ; 20, 52, 29, 916, 175, "20:52:29.916175", "\230\029\167\168\222\088\242\064" ; 13, 0, 5, 702, 388, "13:00:05.702388", "\035\102\246\121\182\218\230\064" ; 20, 57, 7, 993, 824, "20:57:07.993824", "\160\254\179\230\063\106\242\064" ; 8, 33, 43, 793, 917, "08:33:43.793917", "\176\063\137\207\242\025\222\064" ; 7, 20, 50, 145, 794, "07:20:50.145794", "\125\091\176\084\137\212\217\064" ; 17, 51, 5, 96, 259, "17:51:05.096259", "\030\193\141\020\035\097\239\064" ; 17, 44, 18, 705, 999, "17:44:18.705999", "\001\055\139\151\086\046\239\064" ; 14, 22, 26, 432, 757, "14:22:26.432757", "\068\053\037\217\077\068\233\064" ; 22, 48, 20, 840, 429, "22:48:20.840429", "\218\173\101\114\077\011\244\064" ; 10, 22, 33, 139, 279, "10:22:33.139279", "\193\059\249\116\036\061\226\064" ; 8, 6, 54, 266, 18, "08:06:54.266018", "\137\092\112\006\145\135\220\064" ; 19, 49, 13, 203, 955, "19:49:13.203955", "\109\081\102\067\147\107\241\064" ; 7, 19, 17, 729, 858, "07:19:17.729858", "\046\084\254\181\110\189\217\064" ; 19, 42, 13, 94, 171, "19:42:13.094171", "\084\115\185\129\081\081\241\064" ; 12, 58, 5, 717, 201, "12:58:05.717201", "\245\130\079\243\182\203\230\064" ; 11, 22, 1, 120, 793, "11:22:01.120793", "\019\072\137\221\035\251\227\064" ; 17, 12, 28, 943, 75, "17:12:28.943075", "\086\159\171\045\158\063\238\064" ; 7, 38, 26, 285, 817, "07:38:26.285817", "\233\098\211\074\146\220\218\064" ; 17, 24, 22, 352, 345, "17:24:22.352345", "\125\005\105\070\203\152\238\064" ; 15, 57, 59, 732, 376, "15:57:59.732376", "\013\203\159\111\247\016\236\064" ; 23, 26, 44, 726, 120, "23:26:44.726120", "\079\001\048\158\075\155\244\064" ; 2, 32, 38, 378, 257, "02:32:38.378257", "\062\178\185\106\048\227\193\064" ; 14, 36, 30, 967, 516, "14:36:30.967516", "\075\029\228\245\222\173\233\064" ; 16, 59, 16, 539, 231, "16:59:16.539231", "\191\094\097\065\145\220\237\064" ; 6, 58, 27, 195, 851, "06:58:27.195851", "\249\161\210\136\204\132\216\064" ; 7, 50, 37, 872, 61, "07:50:37.872061", "\199\240\216\207\119\147\219\064" ; 15, 53, 1, 593, 628, "15:53:01.593628", "\192\037\000\255\178\235\235\064" ; 15, 2, 25, 982, 614, "15:02:25.982614", "\083\234\146\113\063\112\234\064" ; 17, 10, 30, 216, 630, "17:10:30.216630", "\171\009\162\238\198\048\238\064" ; 1, 32, 59, 930, 603, "01:32:59.930603", "\144\138\255\059\238\203\181\064" ; 18, 7, 22, 450, 827, "18:07:22.450827", "\165\190\044\109\078\219\239\064" ; 21, 34, 7, 868, 765, "21:34:07.868765", "\239\032\118\230\253\244\242\064" ; 12, 0, 55, 736, 385, "12:00:55.736385", "\136\070\119\144\247\030\229\064" ; 15, 18, 36, 885, 915, "15:18:36.885915", "\001\106\106\089\156\233\234\064" ; 1, 30, 4, 931, 89, "01:30:04.931089", "\170\068\217\091\238\028\181\064" ; 19, 54, 11, 867, 848, "19:54:11.867848", "\158\149\180\226\061\126\241\064" ; 20, 14, 1, 127, 637, "20:14:01.127637", "\076\024\205\010\146\200\241\064" ; 16, 30, 35, 92, 545, "16:30:35.092545", "\141\238\032\246\098\005\237\064" ; 8, 42, 24, 450, 263, "08:42:24.450263", "\231\230\027\209\028\156\222\064" ; 3, 35, 30, 371, 143, "03:35:30.371143", "\145\035\157\129\047\065\201\064" ; 8, 35, 45, 746, 928, "08:35:45.746928", "\030\025\171\205\111\056\222\064" ; 4, 22, 12, 430, 516, "04:22:12.430516", "\052\246\037\027\055\186\206\064" ; 21, 58, 33, 455, 725, "21:58:33.455725", "\048\076\166\074\151\080\243\064" ; 1, 35, 15, 660, 391, "01:35:15.660391", "\146\115\098\015\169\083\182\064" ; 18, 35, 33, 252, 232, "18:35:33.252232", "\240\107\036\009\084\087\240\064" ; 4, 47, 30, 136, 59, "04:47:30.136059", "\213\206\048\181\136\216\208\064" ; 18, 45, 22, 847, 289, "18:45:22.847289", "\020\233\126\142\045\124\240\064" ; 23, 58, 52, 220, 772, "23:58:52.220772", "\126\056\072\136\195\019\245\064" ; 16, 1, 0, 828, 88, "16:01:00.828088", "\199\103\178\127\154\039\236\064" ; 12, 17, 24, 32, 10, "12:17:24.032010", "\229\213\057\006\129\154\229\064" ; 7, 59, 3, 885, 182, "07:59:03.885182", "\064\103\210\166\248\017\220\064" ; 12, 29, 55, 511, 70, "12:29:55.511070", "\255\120\175\090\112\248\229\064" ; 15, 35, 1, 116, 437, "15:35:01.116437", "\098\022\218\185\163\100\235\064" ; 19, 7, 54, 814, 685, "19:07:54.814685", "\121\035\243\008\173\208\240\064" ; 4, 32, 35, 175, 873, "04:32:35.175873", "\160\167\001\131\150\241\207\064" ; 12, 35, 14, 269, 410, "12:35:14.269410", "\103\184\001\159\072\032\230\064" ; 23, 8, 50, 239, 23, "23:08:50.239023", "\000\200\009\211\035\088\244\064" ; 3, 39, 41, 721, 861, "03:39:41.721861", "\161\245\240\101\220\190\201\064" ; 13, 10, 46, 846, 384, "13:10:46.846384", "\251\229\147\021\219\042\231\064" ; 17, 11, 4, 762, 276, "17:11:04.762276", "\081\163\144\100\024\053\238\064" ; 15, 5, 20, 869, 937, "15:05:20.869937", "\146\030\134\214\027\134\234\064" ; 1, 27, 28, 757, 521, "01:27:28.757521", "\008\113\229\236\193\128\180\064" ; 7, 46, 7, 912, 203, "07:46:07.912203", "\020\177\136\097\250\079\219\064" ; 5, 30, 31, 0, 590, "05:30:31.000590", "\173\163\170\009\192\093\211\064" ; 4, 17, 14, 187, 236, "04:17:14.187236", "\081\104\089\247\023\037\206\064" ; 3, 53, 24, 574, 775, "03:53:24.574775", "\200\041\058\146\073\090\203\064" ; 6, 21, 7, 558, 440, "06:21:07.558440", "\050\032\123\189\227\084\214\064" ; 12, 41, 1, 251, 762, "12:41:01.251762", "\140\046\111\014\168\075\230\064" ; 5, 5, 33, 889, 497, "05:05:33.889497", "\057\211\132\237\120\231\209\064" ; 18, 24, 24, 864, 123, "18:24:24.864123", "\140\163\114\211\141\045\240\064" ; 3, 40, 29, 12, 252, "03:40:29.012252", "\168\057\121\145\129\214\201\064" ; 10, 56, 20, 913, 590, "10:56:20.913590", "\127\024\033\060\157\058\227\064" ; 5, 19, 12, 177, 988, "05:19:12.177988", "\197\199\039\100\011\180\210\064" ; 6, 27, 39, 431, 473, "06:27:39.431473", "\007\238\064\157\219\182\214\064" ; 21, 23, 12, 632, 962, "21:23:12.632962", "\026\195\156\032\010\204\242\064" ; 17, 20, 31, 172, 130, "17:20:31.172130", "\021\198\022\130\229\123\238\064" ; 22, 24, 52, 988, 427, "22:24:52.988427", "\120\212\152\208\079\179\243\064" ; 7, 52, 55, 292, 326, "07:52:55.292326", "\114\028\120\181\210\181\219\064" ; 2, 6, 50, 588, 865, "02:06:50.588865", "\194\076\219\191\150\186\189\064" ; 17, 2, 37, 184, 464, "17:02:37.184464", "\233\011\033\231\165\245\237\064" ; 3, 52, 28, 541, 151, "03:52:28.541151", "\153\155\111\068\069\062\203\064" ; 5, 10, 7, 856, 804, "05:10:07.856804", "\197\113\224\213\246\043\210\064" ; 14, 38, 38, 560, 334, "14:38:38.560334", "\154\145\065\238\209\189\233\064" ; 5, 54, 48, 179, 136, "05:54:48.179136", "\098\215\246\118\011\202\212\064" ; 23, 56, 18, 426, 8, "23:56:18.426008", "\190\195\237\208\038\010\245\064" ; 9, 47, 53, 228, 305, "09:47:53.228305", "\145\073\070\078\039\057\225\064" ; 20, 26, 1, 150, 233, "20:26:01.150233", "\220\183\090\103\146\245\241\064" ; 18, 33, 30, 443, 81, "18:33:30.443081", "\072\026\220\022\167\079\240\064" ; 7, 26, 20, 541, 586, "07:26:20.541586", "\126\083\088\169\034\039\218\064" ; 10, 43, 18, 494, 218, "10:43:18.494218", "\099\068\162\208\207\216\226\064" ; 1, 27, 30, 724, 853, "01:27:30.724853", "\104\089\247\143\185\130\180\064" ; 9, 47, 1, 817, 330, "09:47:01.817330", "\130\062\145\039\186\050\225\064" ; 16, 21, 26, 957, 569, "16:21:26.957569", "\086\190\103\164\222\192\236\064" ; 9, 15, 34, 23, 120, "09:15:34.023120", "\124\039\102\189\192\070\224\064" ; 4, 16, 26, 136, 368, "04:16:26.136368", "\029\178\129\116\017\013\206\064" ; 10, 51, 1, 952, 553, "10:51:01.952553", "\214\109\080\123\190\018\227\064" ; 13, 6, 33, 3, 674, "13:06:33.003674", "\187\239\024\030\032\011\231\064" ; 15, 50, 34, 976, 14, "15:50:34.976014", "\078\182\129\059\095\217\235\064" ; 3, 53, 35, 168, 488, "03:53:35.168488", "\226\200\003\145\149\095\203\064" ; 2, 9, 32, 87, 728, "02:09:32.087728", "\242\154\087\117\022\092\190\064" ; 5, 29, 20, 992, 393, "05:29:20.992393", "\241\237\093\131\063\076\211\064" ; 1, 42, 5, 797, 66, "01:42:05.797066", "\192\114\132\012\204\237\183\064" ; 19, 44, 39, 771, 301, "19:44:39.771301", "\165\183\063\087\124\090\241\064" ; 6, 44, 46, 455, 515, "06:44:46.455515", "\246\098\040\039\157\183\215\064" ; 18, 46, 14, 856, 849, "18:46:14.856849", "\010\076\167\181\109\127\240\064" ; 19, 7, 15, 619, 292, "19:07:15.619292", "\107\186\158\232\057\206\240\064" ; 5, 47, 59, 273, 46, "05:47:59.273046", "\020\238\149\121\209\099\212\064" ; 21, 50, 31, 221, 563, "21:50:31.221563", "\240\164\133\139\115\050\243\064" ; 1, 39, 12, 536, 537, "01:39:12.536537", "\024\036\125\090\137\064\183\064" ; 9, 51, 42, 485, 79, "09:51:42.485079", "\031\101\196\133\207\085\225\064" ; 16, 5, 55, 394, 964, "16:05:55.394964", "\227\138\139\163\108\076\236\064" ; 23, 47, 54, 570, 211, "23:47:54.570211", "\206\145\149\031\169\234\244\064" ; 20, 34, 57, 602, 488, "20:34:57.602488", "\004\117\202\163\025\023\242\064" ; 17, 33, 56, 557, 800, "17:33:56.557800", "\183\098\127\217\145\224\238\064" ; 10, 38, 50, 716, 763, "10:38:50.716763", "\127\245\184\239\086\183\226\064" ; 5, 18, 9, 125, 537, "05:18:09.125537", "\092\087\204\008\072\164\210\064" ; 11, 40, 21, 215, 414, "11:40:21.215414", "\163\230\171\228\166\132\228\064" ; 11, 49, 9, 45, 788, "11:49:09.045788", "\081\101\024\119\161\198\228\064" ; 13, 42, 19, 362, 370, "13:42:19.362370", "\098\248\136\152\107\023\232\064" ; 21, 48, 9, 153, 726, "21:48:09.153726", "\233\100\169\117\146\041\243\064" ; 16, 43, 14, 199, 689, "16:43:14.199689", "\140\047\218\099\070\100\237\064" ; 0, 26, 56, 43, 265, "00:26:56.043265", "\062\000\169\077\044\064\153\064" ; 7, 26, 56, 119, 721, "07:26:56.119721", "\233\068\130\169\007\048\218\064" ; 17, 30, 0, 760, 630, "17:30:00.760630", "\204\185\020\087\024\195\238\064" ; 20, 56, 22, 622, 393, "20:56:22.622393", "\196\092\082\245\105\103\242\064" ; 8, 55, 48, 629, 106, "08:55:48.629106", "\238\207\069\067\040\101\223\064" ; 21, 46, 56, 868, 437, "21:46:56.868437", "\026\050\030\229\013\037\243\064" ; 5, 46, 14, 546, 399, "05:46:14.546399", "\228\130\051\248\162\073\212\064" ; 19, 46, 49, 175, 737, "19:46:49.175737", "\187\153\209\207\146\098\241\064" ; 20, 13, 19, 207, 578, "20:13:19.207578", "\022\079\061\082\243\197\241\064" ; 5, 15, 11, 392, 368, "05:15:11.392368", "\000\172\142\028\217\119\210\064" ; 4, 9, 52, 109, 894, "04:09:52.109894", "\004\176\001\017\014\072\205\064" ; 4, 23, 31, 246, 390, "04:23:31.246390", "\007\032\181\137\159\225\206\064" ; 2, 0, 15, 81, 199, "02:00:15.081199", "\120\041\117\201\020\047\188\064" ; 14, 28, 53, 92, 895, "14:28:53.092895", "\094\239\254\248\162\116\233\064" ; 17, 21, 22, 872, 336, "17:21:22.872336", "\228\047\045\234\091\130\238\064" ; 19, 5, 0, 135, 440, "19:05:00.135440", "\041\034\195\042\194\197\240\064" ; 7, 3, 56, 245, 901, "07:03:56.245901", "\067\140\215\188\015\215\216\064" ; 5, 9, 34, 926, 509, "05:09:34.926509", "\157\103\236\075\187\035\210\064" ; 1, 38, 30, 691, 877, "01:38:30.691877", "\219\223\217\030\177\022\183\064" ; 18, 7, 50, 408, 956, "18:07:50.408956", "\177\228\042\022\205\222\239\064" ; 23, 48, 40, 975, 381, "23:48:40.975381", "\131\027\041\155\143\237\244\064" ; 16, 3, 41, 194, 221, "16:03:41.194221", "\103\245\014\055\166\059\236\064" ; 12, 15, 19, 138, 13, "12:15:19.138013", "\045\061\154\106\228\138\229\064" ; 21, 24, 36, 359, 631, "21:24:36.359631", "\122\111\012\193\069\209\242\064" ; 15, 8, 48, 319, 139, "15:08:48.319139", "\253\253\098\054\010\160\234\064" ; 19, 5, 46, 740, 979, "19:05:46.740979", "\193\203\012\219\171\200\240\064" ; 5, 26, 17, 793, 718, "05:26:17.793718", "\016\149\070\204\114\030\211\064" ; 16, 45, 6, 434, 529, "16:45:06.434529", "\133\092\169\231\077\114\237\064" ; 13, 53, 49, 344, 201, "13:53:49.344201", "\200\208\177\003\171\109\232\064" ; 17, 26, 22, 226, 790, "17:26:22.226790", "\034\026\221\065\199\167\238\064" ; 14, 30, 12, 428, 322, "14:30:12.428322", "\197\086\208\180\141\126\233\064" ; 18, 34, 56, 307, 581, "18:34:56.307581", "\254\013\218\235\004\085\240\064" ; 13, 2, 2, 268, 928, "13:02:02.268928", "\159\228\014\155\072\233\230\064" ; 20, 8, 15, 688, 795, "20:08:15.688795", "\234\231\077\005\251\178\241\064" ; 4, 5, 3, 425, 392, "04:05:03.425392", "\253\187\062\115\182\183\204\064" ; 12, 39, 44, 16, 198, "12:39:44.016198", "\009\171\177\132\000\066\230\064" ; 0, 36, 53, 734, 898, "00:36:53.734898", "\202\247\140\068\120\075\161\064" ; 11, 45, 43, 101, 195, "11:45:43.101195", "\241\075\253\060\227\172\228\064" ; 17, 8, 17, 284, 383, "17:08:17.284383", "\145\096\170\025\041\032\238\064" ; 0, 3, 37, 477, 388, "00:03:37.477388", "\023\240\050\195\070\047\107\064" ; 10, 11, 31, 264, 956, "10:11:31.264956", "\093\001\133\122\104\234\225\064" ; 18, 58, 49, 2, 596, "18:58:49.002596", "\113\026\162\010\144\174\240\064" ; 19, 26, 38, 187, 89, "19:26:38.187089", "\007\009\081\254\226\022\241\064" ; 23, 29, 20, 720, 722, "23:29:20.720722", "\184\202\019\136\011\165\244\064" ; 20, 45, 5, 183, 655, "20:45:05.183655", "\172\057\064\240\018\061\242\064" ; 16, 7, 57, 389, 943, "16:07:57.389943", "\010\190\105\122\172\091\236\064" ; 9, 24, 9, 328, 615, "09:24:09.328615", "\191\154\003\132\042\135\224\064" ; 12, 13, 38, 847, 43, "12:13:38.847043", "\234\235\249\026\091\126\229\064" ; 21, 49, 21, 792, 835, "21:49:21.792835", "\194\192\115\175\028\046\243\064" ; 12, 51, 8, 311, 189, "12:51:08.311189", "\060\162\066\245\137\151\230\064" ; 7, 38, 58, 584, 654, "07:38:58.584654", "\094\156\248\106\165\228\218\064" ; 6, 36, 48, 397, 601, "06:36:48.397601", "\247\118\075\114\025\064\215\064" ; 7, 42, 33, 265, 165, "07:42:33.265165", "\195\158\118\248\080\026\219\064" ; 16, 40, 45, 451, 350, "16:40:45.451350", "\034\142\117\113\174\081\237\064" ; 18, 35, 41, 932, 938, "18:35:41.932938", "\115\101\080\237\222\087\240\064" ; 17, 0, 10, 766, 172, "17:00:10.766172", "\100\036\123\132\088\227\237\064" ; 18, 22, 14, 675, 972, "18:22:14.675972", "\016\004\200\208\106\037\240\064" ; 21, 51, 53, 133, 295, "21:51:53.133295", "\028\240\249\033\146\055\243\064" ; 7, 34, 28, 884, 587, "07:34:28.884587", "\221\202\018\157\056\161\218\064" ; 1, 57, 37, 260, 31, "01:57:37.260031", "\242\064\100\145\066\145\187\064" ; 7, 47, 7, 789, 814, "07:47:07.789814", "\251\004\080\140\242\094\219\064" ; 15, 34, 22, 915, 933, "15:34:22.915933", "\011\185\082\079\221\095\235\064" ; 14, 38, 58, 105, 328, "14:38:58.105328", "\108\211\216\094\067\192\233\064" ; 4, 28, 12, 891, 268, "04:28:12.891268", "\252\223\017\021\114\110\207\064" ; 18, 28, 50, 720, 991, "18:28:50.720991", "\219\219\045\137\043\062\240\064" ; 1, 1, 58, 771, 270, "01:01:58.771270", "\198\196\230\227\138\013\173\064" ; 11, 16, 30, 651, 496, "11:16:30.651496", "\175\035\014\217\212\209\227\064" ; 0, 47, 37, 387, 663, "00:47:37.387663", "\189\197\195\123\198\082\166\064" ; 19, 14, 44, 745, 911, "19:14:44.745911", "\107\095\064\239\075\234\240\064" ; 0, 28, 0, 377, 565, "00:28:00.377565", "\117\060\102\160\130\065\154\064" ; 5, 56, 50, 692, 914, "05:56:50.692914", "\060\246\179\088\172\232\212\064" ; 2, 25, 6, 424, 929, "02:25:06.424929", "\016\207\018\100\054\001\193\064" ; 16, 46, 56, 943, 669, "16:46:56.943669", "\168\084\137\050\030\128\237\064" ; 16, 5, 46, 661, 118, "16:05:46.661118", "\154\239\224\039\085\075\236\064" ; 1, 55, 53, 212, 592, "01:55:53.212592", "\101\231\109\108\054\041\187\064" ; 8, 56, 8, 637, 756, "08:56:08.637756", "\181\138\254\208\040\106\223\064" ; 23, 15, 30, 326, 385, "23:15:30.326385", "\079\122\223\056\037\113\244\064" ; 19, 27, 23, 810, 110, "19:27:23.810110", "\066\231\053\246\188\025\241\064" ; 13, 1, 28, 32, 211, "13:01:28.032211", "\242\092\223\007\001\229\230\064" ; 1, 28, 39, 602, 686, "01:28:39.602686", "\194\051\161\073\154\199\180\064" ; 14, 56, 9, 75, 613, "14:56:09.075613", "\068\244\107\107\034\065\234\064" ; 4, 11, 8, 360, 764, "04:11:08.360764", "\202\198\131\045\046\110\205\064" ; 17, 33, 25, 955, 585, "17:33:25.955585", "\114\254\038\148\190\220\238\064" ; 6, 44, 54, 8, 395, "06:44:54.008395", "\157\046\139\137\128\185\215\064" ; 2, 8, 29, 225, 316, "02:08:29.225316", "\068\051\079\174\057\029\190\064" ; 11, 9, 36, 955, 879, "11:09:36.955879", "\126\142\143\150\030\158\227\064" ; 19, 1, 2, 30, 743, "19:01:02.030743", "\057\095\236\125\224\182\240\064" ; 20, 52, 31, 293, 285, "20:52:31.293285", "\183\156\075\177\244\088\242\064" ; 2, 30, 6, 917, 602, "02:30:06.917602", "\095\122\251\115\117\151\193\064" ; 14, 12, 19, 590, 167, "14:12:19.590167", "\133\231\165\226\114\248\232\064" ; 14, 55, 15, 861, 538, "14:55:15.861538", "\200\035\184\145\123\058\234\064" ; 0, 46, 8, 409, 104, "00:46:08.409104", "\084\089\020\118\209\160\165\064" ; 12, 18, 59, 699, 53, "12:18:59.699053", "\166\101\164\094\118\166\229\064" ; 20, 49, 14, 611, 504, "20:49:14.611504", "\022\107\184\200\169\076\242\064" ; 17, 59, 16, 595, 292, "17:59:16.595292", "\242\206\161\012\147\158\239\064" ; 12, 42, 52, 150, 986, "12:42:52.150986", "\133\151\224\212\132\089\230\064" ; 21, 53, 4, 80, 811, "21:53:04.080811", "\163\121\000\075\001\060\243\064" ; 20, 10, 27, 675, 29, "20:10:27.675029", "\110\053\235\204\058\187\241\064" ; 20, 7, 22, 57, 242, "20:07:22.057242", "\095\150\118\234\160\175\241\064" ; 13, 15, 49, 288, 93, "13:15:49.288093", "\167\207\014\056\169\080\231\064" ; 21, 30, 0, 286, 910, "21:30:00.286910", "\174\240\046\151\132\229\242\064" ; 14, 0, 10, 821, 666, "14:00:10.821666", "\200\126\022\075\090\157\232\064" ; 8, 11, 14, 934, 73, "08:11:14.934073", "\197\030\218\199\187\200\220\064" ; 15, 34, 31, 856, 854, "15:34:31.856854", "\110\020\089\107\251\096\235\064" ; 20, 45, 26, 234, 301, "20:45:26.234301", "\198\103\178\191\099\062\242\064" ; 20, 19, 28, 425, 726, "20:19:28.425726", "\241\016\198\207\006\221\241\064" ; 3, 55, 28, 688, 491, "03:55:28.688491", "\076\028\121\032\088\152\203\064" ; 6, 51, 46, 160, 272, "06:51:46.160272", "\158\125\229\065\138\032\216\064" ; 9, 5, 16, 264, 444, "09:05:16.264444", "\232\134\166\236\016\243\223\064" ; 22, 57, 48, 675, 215, "22:57:48.675215", "\108\062\174\205\202\046\244\064" ; 15, 27, 34, 145, 483, "15:27:34.145483", "\228\246\203\167\196\044\235\064" ; 8, 37, 31, 356, 674, "08:37:31.356674", "\085\047\191\211\214\082\222\064" ; 11, 26, 15, 263, 517, "11:26:15.263517", "\030\052\187\110\232\026\228\064" ; 15, 52, 20, 987, 488, "15:52:20.987488", "\038\111\128\153\159\230\235\064" ; 10, 53, 49, 163, 305, "10:53:49.163305", "\073\104\203\057\165\039\227\064" ; 18, 38, 13, 35, 857, "18:38:13.035857", "\038\202\222\146\080\097\240\064" ; 7, 29, 33, 565, 71, "07:29:33.565071", "\058\142\031\042\100\087\218\064" ; 2, 55, 44, 999, 77, "02:55:44.999077", "\152\080\193\225\127\152\196\064" ; 11, 32, 29, 57, 66, "11:32:29.057066", "\119\019\124\211\161\073\228\064" ; 5, 9, 48, 929, 985, "05:09:48.929985", "\049\206\223\132\059\039\210\064" ; 2, 33, 50, 196, 442, "02:33:50.196442", "\200\238\002\037\025\007\194\064" ; 2, 30, 34, 733, 849, "02:30:34.733849", "\154\151\195\238\093\165\193\064" ; 8, 12, 21, 776, 400, "08:12:21.776400", "\040\160\137\176\113\217\220\064" ; 1, 28, 57, 873, 294, "01:28:57.873294", "\203\017\050\144\223\217\180\064" ; 1, 13, 30, 604, 202, "01:13:30.604202", "\046\118\251\172\154\058\177\064" ; 10, 15, 58, 845, 395, "10:15:58.845395", "\167\208\121\013\219\011\226\064" ; 9, 13, 41, 880, 714, "09:13:41.880714", "\100\032\207\046\188\056\224\064" ; 7, 50, 24, 226, 273, "07:50:24.226273", "\190\191\065\123\014\144\219\064" ; 1, 20, 4, 47, 986, "01:20:04.047986", "\170\124\207\072\012\196\178\064" ; 22, 27, 37, 621, 85, "22:27:37.621085", "\049\211\246\239\153\189\243\064" ; 19, 42, 7, 130, 952, "19:42:07.130952", "\214\031\097\024\242\080\241\064" ; 4, 2, 11, 437, 937, "04:02:11.437937", "\091\210\081\014\184\097\204\064" ; 8, 12, 55, 35, 675, "08:12:55.035675", "\146\203\127\072\194\225\220\064" ; 22, 28, 27, 825, 109, "22:28:27.825109", "\170\126\165\051\189\192\243\064" ; 19, 42, 32, 642, 414, "19:42:32.642414", "\008\231\083\071\138\082\241\064" ; 15, 17, 58, 246, 462, "15:17:58.246462", "\183\070\004\227\199\228\234\064" ; 5, 3, 10, 363, 480, "05:03:10.363480", "\048\158\065\067\151\195\209\064" ; 22, 46, 27, 901, 845, "22:46:27.901845", "\209\005\245\109\062\004\244\064" ; 8, 7, 38, 122, 226, "08:07:38.122226", "\046\000\141\210\135\146\220\064" ; 14, 56, 48, 254, 238, "14:56:48.254238", "\237\186\183\034\008\070\234\064" ; 23, 20, 46, 473, 591, "23:20:46.473591", "\011\040\212\147\231\132\244\064" ; 13, 51, 57, 25, 61, "13:51:57.025061", "\237\185\076\205\160\095\232\064" ; 18, 31, 18, 665, 64, "18:31:18.665064", "\028\038\026\164\106\071\240\064" ; 23, 55, 10, 561, 42, "23:55:10.561042", "\027\045\007\250\232\005\245\064" ; 16, 28, 46, 160, 616, "16:28:46.160616", "\103\042\196\035\197\247\236\064" ; 20, 42, 24, 556, 322, "20:42:24.556322", "\193\229\177\230\008\051\242\064" ; 5, 4, 30, 874, 937, "05:04:30.874937", "\068\194\247\254\183\215\209\064" ; 1, 53, 2, 749, 718, "01:53:02.749718", "\057\211\132\237\191\126\186\064" ; 20, 54, 39, 482, 641, "20:54:39.482641", "\236\196\229\184\247\096\242\064" ; 18, 42, 3, 202, 362, "18:42:03.202362", "\192\239\223\060\179\111\240\064" ; 8, 47, 36, 344, 297, "08:47:36.344297", "\199\072\246\008\022\234\222\064" ; 16, 23, 13, 424, 462, "16:23:13.424462", "\013\085\049\149\045\206\236\064" ; 2, 14, 34, 60, 631, "02:14:34.060631", "\032\098\131\133\015\138\191\064" ; 11, 13, 7, 58, 193, "11:13:07.058193", "\251\144\183\220\097\184\227\064" ; 1, 57, 15, 165, 811, "01:57:15.165811", "\081\246\150\114\042\123\187\064" ; 14, 58, 15, 837, 992, "14:58:15.837992", "\074\153\212\208\250\080\234\064" ; 17, 0, 57, 916, 89, "17:00:57.916089", "\231\224\153\080\061\233\237\064" ; 8, 0, 46, 426, 773, "08:00:46.426773", "\116\179\063\080\155\043\220\064" ; 9, 55, 14, 185, 69, "09:55:14.185069", "\208\210\021\236\069\112\225\064" ; 4, 32, 16, 32, 533, "04:32:16.032533", "\133\149\010\042\004\232\207\064" ; 7, 6, 17, 400, 517, "07:06:17.400517", "\032\014\018\162\089\250\216\064" ; 5, 22, 25, 940, 926, "05:22:25.940926", "\125\175\033\056\124\228\210\064" ; 1, 38, 49, 913, 629, "01:38:49.913629", "\173\019\151\227\233\041\183\064" ; 15, 34, 32, 246, 594, "15:34:32.246594", "\172\025\025\228\007\097\235\064" ; 5, 50, 9, 999, 964, "05:50:09.999964", "\075\001\105\255\127\132\212\064" ; 17, 27, 8, 231, 970, "17:27:08.231970", "\117\089\076\108\135\173\238\064" ; 5, 57, 41, 102, 144, "05:57:41.102144", "\223\252\134\137\070\245\212\064" ; 20, 44, 36, 330, 602, "20:44:36.330602", "\160\082\037\074\069\059\242\064" ; 19, 21, 0, 443, 26, "19:21:00.443026", "\084\110\162\022\199\001\241\064" ; 12, 24, 45, 607, 212, "12:24:45.607212", "\056\220\071\110\179\209\229\064" ; 2, 45, 26, 922, 518, "02:45:26.922518", "\253\223\017\021\118\099\195\064" ; 9, 58, 6, 564, 249, "09:58:06.564249", "\057\235\083\014\210\133\225\064" ; 9, 27, 41, 765, 382, "09:27:41.765382", "\094\100\002\126\184\161\224\064" ; 12, 26, 41, 874, 693, "12:26:41.874693", "\162\044\124\253\059\224\229\064" ; 20, 43, 26, 726, 706, "20:43:26.726706", "\125\120\150\160\235\054\242\064" ; 6, 19, 59, 680, 963, "06:19:59.680963", "\178\213\229\148\235\067\214\064" ; 16, 54, 7, 145, 3, "16:54:07.145003", "\218\084\221\163\228\181\237\064" ; 15, 37, 40, 74, 679, "15:37:40.074679", "\214\054\197\099\130\120\235\064" ; 10, 18, 52, 199, 40, "10:18:52.199040", "\083\034\137\094\134\033\226\064" ; 5, 37, 18, 334, 965, "05:37:18.334965", "\019\010\017\112\149\195\211\064" ; 19, 21, 25, 633, 590, "19:21:25.633590", "\145\068\047\035\090\003\241\064" ; 7, 31, 25, 132, 584, "07:31:25.132584", "\255\153\065\124\072\115\218\064" ; 13, 51, 46, 557, 151, "13:51:46.557151", "\126\085\046\212\081\094\232\064" ; 11, 33, 59, 982, 848, "11:33:59.982848", "\031\166\125\115\255\084\228\064" ; 2, 35, 57, 456, 400, "02:35:57.456400", "\243\176\080\107\186\070\194\064" ; 2, 12, 24, 149, 745, "02:12:24.149745", "\190\053\176\085\038\008\191\064" ; 11, 10, 24, 158, 346, "11:10:24.158346", "\111\161\043\017\005\164\227\064" ; 17, 52, 8, 99, 403, "17:52:08.099403", "\068\051\079\046\003\105\239\064" ; 2, 10, 55, 631, 45, "02:10:55.631045", "\078\069\042\140\161\175\190\064" ; 14, 21, 3, 389, 821, "14:21:03.389821", "\202\227\105\121\236\057\233\064" ; 1, 34, 37, 293, 876, "01:34:37.293876", "\020\033\117\059\075\045\182\064" ; 2, 36, 35, 47, 639, "02:36:35.047639", "\130\229\008\025\134\089\194\064" ; 16, 55, 13, 653, 242, "16:55:13.653242", "\076\196\091\231\052\190\237\064" ; 14, 12, 39, 845, 847, "14:12:39.845847", "\078\186\045\017\251\250\232\064" ; 19, 43, 32, 260, 366, "19:43:32.260366", "\239\137\117\042\068\086\241\064" ; 14, 54, 20, 614, 203, "14:54:20.614203", "\196\012\141\167\147\051\234\064" ; 11, 47, 11, 465, 451, "11:47:11.465451", "\220\126\249\228\238\183\228\064" ; 12, 27, 11, 223, 77, "12:27:11.223077", "\111\096\114\035\231\227\229\064" ; 4, 52, 32, 278, 199, "04:52:32.278199", "\177\045\003\206\017\036\209\064" ; 15, 37, 1, 393, 100, "15:37:01.393100", "\129\115\070\148\172\115\235\064" ; 17, 14, 44, 84, 648, "17:14:44.084648", "\246\184\111\181\130\080\238\064" ; 12, 11, 38, 813, 724, "12:11:38.813724", "\255\233\006\010\090\111\229\064" ; 18, 52, 21, 290, 35, "18:52:21.290035", "\123\189\251\163\084\150\240\064" ; 12, 57, 55, 10, 800, "12:57:55.010800", "\218\061\121\088\096\202\230\064" ; 5, 26, 16, 278, 157, "05:26:16.278157", "\137\004\083\205\017\030\211\064" ; 16, 51, 27, 371, 332, "16:51:27.371332", "\127\165\243\225\235\161\237\064" ; 7, 9, 58, 149, 638, "07:09:58.149638", "\016\067\171\147\137\049\217\064" ; 7, 59, 44, 757, 95, "07:59:44.757095", "\062\150\062\116\048\028\220\064" ; 2, 7, 16, 386, 999, "02:07:16.386999", "\150\208\093\018\099\212\189\064" ; 16, 31, 55, 34, 857, "16:31:55.034857", "\097\109\140\029\097\015\237\064" ; 8, 0, 11, 26, 29, "08:00:11.026029", "\240\137\117\170\193\034\220\064" ; 11, 32, 2, 940, 388, "11:32:02.940388", "\050\147\168\023\094\070\228\064" ; 2, 9, 27, 564, 905, "02:09:27.564905", "\089\052\157\157\144\087\190\064" ; 3, 38, 15, 8, 563, "03:38:15.008563", "\122\166\151\024\129\147\201\064" ; 14, 50, 7, 458, 605, "14:50:07.458605", "\153\100\228\172\238\019\234\064" ; 5, 39, 23, 903, 96, "05:39:23.903096", "\073\042\083\204\249\226\211\064" ; 2, 21, 10, 871, 215, "02:21:10.871215", "\100\030\249\131\111\139\192\064" ; 21, 15, 28, 517, 531, "21:15:28.517531", "\251\149\206\071\008\175\242\064" ; 11, 13, 23, 35, 60, "11:13:23.035060", "\045\038\054\031\097\186\227\064" ; 13, 25, 55, 531, 471, "13:25:55.531471", "\121\120\207\001\113\156\231\064" ; 6, 52, 45, 236, 531, "06:52:45.236531", "\096\235\082\035\079\047\216\064" ; 4, 1, 22, 737, 613, "04:01:22.737613", "\013\080\026\106\094\073\204\064" ; 21, 51, 47, 236, 363, "21:51:47.236363", "\176\145\036\200\051\055\243\064" ; 10, 46, 33, 72, 489, "10:46:33.072489", "\138\115\212\081\034\241\226\064" ; 5, 44, 39, 748, 486, "05:44:39.748486", "\225\210\049\231\239\049\212\064" ; 21, 11, 37, 449, 376, "21:11:37.449376", "\121\227\164\048\151\160\242\064" ; 5, 25, 3, 89, 17, "05:25:03.089017", "\242\091\116\178\197\011\211\064" ; 17, 35, 51, 339, 486, "17:35:51.339486", "\110\190\017\221\234\238\238\064" ; 3, 53, 47, 195, 611, "03:53:47.195611", "\222\255\199\009\153\101\203\064" ; 4, 53, 6, 118, 135, "04:53:06.118135", "\096\026\134\143\135\044\209\064" ; 9, 4, 17, 451, 811, "09:04:17.451811", "\063\175\120\234\092\228\223\064" ; 7, 36, 31, 461, 233, "07:36:31.461233", "\181\106\215\132\221\191\218\064" ; 13, 12, 51, 826, 325, "13:12:51.826325", "\092\032\065\113\122\058\231\064" ; 10, 25, 39, 260, 83, "10:25:39.260083", "\104\149\153\082\104\084\226\064" ; 19, 41, 48, 932, 761, "19:41:48.932761", "\096\204\150\236\206\079\241\064" ; 10, 44, 2, 77, 837, "10:44:02.077837", "\045\005\164\125\066\222\226\064" ; 21, 2, 20, 272, 462, "21:02:20.272462", "\054\029\001\092\196\125\242\064" ; 7, 30, 4, 977, 724, "07:30:04.977724", "\033\175\007\147\062\095\218\064" ; 23, 55, 38, 464, 629, "23:55:38.464629", "\125\209\030\111\167\007\245\064" ; 13, 47, 19, 946, 104, "13:47:19.946104", "\084\229\123\070\254\060\232\064" ; 14, 58, 38, 551, 362, "14:58:38.551362", "\200\235\193\164\209\083\234\064" ; 15, 3, 5, 512, 600, "15:03:05.512600", "\126\029\056\103\048\117\234\064" ; 3, 18, 8, 993, 213, "03:18:08.993213", "\123\132\154\033\127\056\199\064" ; 23, 45, 19, 848, 170, "23:45:19.848170", "\183\180\026\146\253\224\244\064" ; 4, 39, 55, 749, 394, "04:39:55.749394", "\116\064\018\246\239\102\208\064" ; 8, 23, 41, 264, 662, "08:23:41.264662", "\159\226\056\240\080\131\221\064" ; 1, 45, 0, 64, 771, "01:45:00.064771", "\187\014\213\148\016\156\184\064" ; 13, 57, 6, 353, 994, "13:57:06.353994", "\160\057\235\083\075\134\232\064" ; 19, 53, 28, 963, 254, "19:53:28.963254", "\188\006\125\105\143\123\241\064" ; 18, 5, 40, 495, 355, "18:05:40.495355", "\157\186\242\217\143\206\239\064" ; 12, 29, 23, 744, 768, "12:29:23.744768", "\099\179\035\213\119\244\229\064" ; 10, 43, 14, 355, 267, "10:43:14.355267", "\076\230\088\094\075\216\226\064" ; 3, 26, 35, 961, 174, "03:26:35.961174", "\226\231\191\007\251\053\200\064" ; 0, 18, 7, 430, 249, "00:18:07.430249", "\140\160\049\147\184\253\144\064" ; 1, 30, 48, 353, 812, "01:30:48.353812", "\239\088\108\147\090\072\181\064" ; 22, 24, 53, 718, 774, "22:24:53.718774", "\115\042\025\128\091\179\243\064" ; 14, 22, 24, 441, 56, "14:22:24.441056", "\246\120\033\029\014\068\233\064" ; 5, 0, 24, 6, 570, "05:00:24.006570", "\201\147\164\107\000\154\209\064" ; 17, 53, 27, 867, 798, "17:53:27.867798", "\177\079\000\197\251\114\239\064" ; 11, 16, 31, 595, 319, "11:16:31.595319", "\118\110\218\012\243\209\227\064" ; 19, 29, 31, 965, 798, "19:29:31.965798", "\136\154\232\115\191\033\241\064" ; 21, 34, 27, 85, 974, "21:34:27.085974", "\229\069\038\096\049\246\242\064" ; 22, 16, 41, 34, 785, "22:16:41.034785", "\086\183\122\142\144\148\243\064" ; 23, 13, 56, 220, 336, "23:13:56.220336", "\162\010\127\134\067\107\244\064" ; 18, 45, 36, 268, 70, "18:45:36.268070", "\176\196\003\074\004\125\240\064" ; 19, 38, 52, 5, 160, "19:38:52.005160", "\244\166\034\021\192\068\241\064" ; 13, 5, 19, 114, 465, "13:05:19.114465", "\241\128\178\169\227\001\231\064" ; 8, 24, 49, 865, 862, "08:24:49.865862", "\055\115\072\106\119\148\221\064" ; 2, 9, 55, 478, 735, "02:09:55.478735", "\115\128\096\142\122\115\190\064" ; 12, 48, 42, 644, 230, "12:48:42.644230", "\163\059\136\157\084\133\230\064" ; 4, 31, 55, 672, 132, "04:31:55.672132", "\076\223\107\008\214\221\207\064" ; 19, 27, 34, 697, 314, "19:27:34.697314", "\145\185\050\040\107\026\241\064" ; 21, 57, 57, 425, 127, "21:57:57.425127", "\027\248\081\205\086\078\243\064" ; 15, 9, 54, 506, 850, "15:09:54.506850", "\191\125\029\056\080\168\234\064" ; 4, 0, 10, 838, 142, "04:00:10.838142", "\180\175\060\072\107\037\204\064" ; 9, 5, 26, 499, 90, "09:05:26.499090", "\241\046\023\241\159\245\223\064" ; 7, 36, 24, 444, 448, "07:36:24.444448", "\049\006\214\113\028\190\218\064" ; 14, 24, 10, 612, 447, "14:24:10.612447", "\113\115\042\153\083\081\233\064" ; 0, 49, 54, 597, 927, "00:49:54.597927", "\203\220\124\035\050\101\167\064" ; 23, 15, 13, 272, 92, "23:15:13.272092", "\024\036\125\090\020\112\244\064" ; 4, 38, 31, 931, 543, "04:38:31.931543", "\244\135\102\158\251\081\208\064" ; 15, 58, 19, 549, 557, "15:58:19.549557", "\201\143\248\149\113\019\236\064" ; 20, 25, 53, 610, 889, "20:25:53.610889", "\072\139\051\198\025\245\241\064" ; 12, 6, 26, 504, 551, "12:06:26.504551", "\133\035\072\037\080\072\229\064" ; 4, 4, 34, 388, 179, "04:04:34.388179", "\000\119\217\175\049\169\204\064" ; 1, 51, 10, 596, 452, "01:51:10.596452", "\162\009\020\177\152\014\186\064" ; 17, 14, 19, 617, 478, "17:14:19.617478", "\000\057\097\194\115\077\238\064" ; 5, 50, 31, 695, 275, "05:50:31.695275", "\174\182\098\127\236\137\212\064" ; 7, 50, 34, 926, 831, "07:50:34.926831", "\123\248\050\081\187\146\219\064" ; 2, 38, 14, 759, 185, "02:38:14.759185", "\079\093\249\044\097\139\194\064" ; 20, 20, 29, 613, 624, "20:20:29.613624", "\064\102\103\209\217\224\241\064" ; 21, 1, 51, 395, 273, "21:01:51.395273", "\000\200\009\083\246\123\242\064" ; 18, 17, 13, 4, 6, "18:17:13.004006", "\112\152\104\016\144\018\240\064" ; 10, 20, 52, 193, 140, "10:20:52.193140", "\241\239\051\046\134\048\226\064" ; 3, 2, 41, 632, 20, "03:02:41.632020", "\053\007\008\230\208\104\197\064" ; 4, 13, 48, 950, 339, "04:13:48.950339", "\143\086\181\164\121\190\205\064" ; 3, 37, 47, 512, 674, "03:37:47.512674", "\194\055\077\159\193\133\201\064" ; 4, 18, 31, 562, 66, "04:18:31.562066", "\025\088\199\241\199\075\206\064" ; 17, 25, 59, 331, 580, "17:25:59.331580", "\000\169\077\156\234\164\238\064" ; 16, 9, 35, 550, 106, "16:09:35.550106", "\235\229\119\154\241\103\236\064" ; 5, 41, 54, 643, 903, "05:41:54.643903", "\179\237\180\053\169\008\212\064" ; 22, 44, 41, 85, 398, "22:44:41.085398", "\019\075\202\093\145\253\243\064" ; 0, 16, 8, 7, 732, "00:16:08.007732", "\015\121\203\213\015\064\142\064" ; 14, 25, 13, 759, 953, "14:25:13.759953", "\048\244\136\081\056\089\233\064" ; 3, 2, 1, 242, 241, "03:02:01.242241", "\096\202\192\001\159\084\197\064" ; 23, 40, 45, 234, 513, "23:40:45.234513", "\024\180\144\192\211\207\244\064" ; 20, 57, 53, 908, 764, "20:57:53.908764", "\188\030\076\138\030\109\242\064" ; 23, 45, 48, 622, 257, "23:45:48.622257", "\140\193\195\244\201\226\244\064" ; 20, 16, 10, 101, 564, "20:16:10.101564", "\167\146\001\160\161\208\241\064" ; 20, 22, 57, 921, 584, "20:22:57.921584", "\072\221\206\190\030\234\241\064" ; 19, 14, 5, 184, 533, "19:14:05.184533", "\000\224\216\243\210\231\240\064" ; 0, 34, 44, 619, 88, "00:34:44.619088", "\177\050\026\249\060\073\160\064" ; 1, 10, 22, 812, 743, "01:10:22.812743", "\013\221\236\015\208\126\176\064" ; 3, 17, 22, 721, 531, "03:17:22.721531", "\006\184\032\091\092\033\199\064" ; 19, 44, 22, 258, 971, "19:44:22.258971", "\122\198\190\036\100\089\241\064" ; 22, 41, 28, 57, 299, "22:41:28.057299", "\050\091\178\234\128\241\243\064" ; 21, 22, 59, 850, 960, "21:22:59.850960", "\164\059\136\157\061\203\242\064" ; 2, 32, 51, 819, 974, "02:32:51.819974", "\201\116\232\244\232\233\193\064" ; 9, 40, 35, 9, 993, "09:40:35.009993", "\006\215\220\081\096\002\225\064" ; 17, 31, 52, 178, 594, "17:31:52.178594", "\168\195\010\183\005\209\238\064" ; 3, 23, 52, 327, 53, "03:23:52.327053", "\135\105\223\220\041\228\199\064" ; 23, 52, 23, 687, 648, "23:52:23.687648", "\115\048\155\000\123\251\244\064" ; 12, 52, 2, 29, 145, "12:52:02.029145", "\187\126\193\238\064\158\230\064" ; 14, 38, 29, 896, 639, "14:38:29.896639", "\170\069\068\177\188\188\233\064" ; 2, 9, 18, 148, 791, "02:09:18.148791", "\241\190\042\023\038\078\190\064" ; 8, 59, 45, 364, 72, "08:59:45.364072", "\089\165\244\076\087\160\223\064" ; 4, 27, 26, 104, 639, "04:27:26.104639", "\113\141\207\100\013\087\207\064" ; 1, 12, 53, 270, 436, "01:12:53.270436", "\170\047\075\059\069\021\177\064" ; 22, 25, 7, 846, 26, "22:25:07.846026", "\025\143\082\137\061\180\243\064" ; 18, 50, 6, 381, 81, "18:50:06.381081", "\002\100\232\024\230\141\240\064" ; 10, 18, 19, 728, 554, "10:18:19.728554", "\108\122\080\080\119\029\226\064" ; 15, 50, 41, 966, 330, "15:50:41.966330", "\101\228\044\236\062\218\235\064" ; 19, 31, 6, 514, 929, "19:31:06.514929", "\236\048\038\061\168\039\241\064" ; 17, 49, 5, 126, 57, "17:49:05.126057", "\141\176\168\008\036\082\239\064" ; 9, 37, 4, 746, 240, "09:37:04.746240", "\095\181\050\225\023\232\224\064" ; 19, 49, 30, 967, 213, "19:49:30.967213", "\181\086\180\121\175\108\241\064" ; 9, 20, 56, 221, 197, "09:20:56.221197", "\031\187\011\020\007\111\224\064" ; 9, 1, 0, 685, 183, "09:01:00.685183", "\050\204\009\218\043\179\223\064" ; 18, 50, 58, 974, 12, "18:50:58.974012", "\095\155\141\149\047\145\240\064" ; 9, 55, 30, 745, 593, "09:55:30.745593", "\228\217\229\219\087\114\225\064" ; 11, 26, 56, 756, 745, "11:26:56.756745", "\077\074\065\055\024\032\228\064" ; 6, 14, 56, 325, 267, "06:14:56.325267", "\222\173\044\209\020\248\213\064" ; 1, 56, 24, 133, 369, "01:56:24.133369", "\077\133\120\036\034\072\187\064" ; 23, 11, 30, 34, 244, "23:11:30.034244", "\193\111\067\140\032\098\244\064" ; 23, 56, 10, 232, 232, "23:56:10.232232", "\210\230\056\183\163\009\245\064" ; 8, 54, 44, 728, 473, "08:54:44.728473", "\193\055\077\159\046\085\223\064" ; 16, 41, 53, 262, 452, "16:41:53.262452", "\153\188\001\102\040\090\237\064" ; 22, 20, 4, 972, 321, "22:20:04.972321", "\003\119\160\142\079\161\243\064" ; 11, 17, 24, 232, 705, "11:17:24.232705", "\148\193\081\114\135\216\227\064" ; 17, 50, 51, 910, 193, "17:50:51.910193", "\002\018\077\032\125\095\239\064" ; 13, 5, 56, 208, 321, "13:05:56.208321", "\066\205\144\170\134\006\231\064" ; 17, 21, 51, 237, 145, "17:21:51.237145", "\109\028\177\150\231\133\238\064" ; 2, 2, 4, 352, 211, "02:02:04.352211", "\074\006\128\042\090\156\188\064" ; 16, 48, 36, 707, 841, "16:48:36.707841", "\057\043\162\166\150\140\237\064" ; 19, 12, 39, 116, 665, "19:12:39.116665", "\121\030\220\221\113\226\240\064" ; 13, 4, 25, 521, 175, "13:04:25.521175", "\144\049\119\173\048\251\230\064" ; 7, 0, 31, 604, 452, "07:00:31.604452", "\000\113\087\175\230\163\216\064" ; 6, 9, 38, 172, 75, "06:09:38.172075", "\093\220\070\003\139\168\213\064" ; 7, 41, 7, 991, 701, "07:41:07.991701", "\155\120\007\120\255\004\219\064" ; 5, 32, 26, 458, 852, "05:32:26.458852", "\109\199\212\093\157\122\211\064" ; 8, 25, 5, 260, 628, "08:25:05.260628", "\027\016\033\174\080\152\221\064" ; 6, 46, 48, 907, 717, "06:46:48.907717", "\065\011\009\024\058\214\215\064" ; 17, 11, 12, 509, 44, "17:11:12.509044", "\135\164\022\074\016\054\238\064" ; 0, 7, 7, 877, 655, "00:07:07.877655", "\188\034\248\223\010\190\122\064" ; 2, 2, 13, 653, 851, "02:02:13.653851", "\117\117\199\098\167\165\188\064" ; 12, 57, 38, 613, 507, "12:57:38.613507", "\155\110\217\161\083\200\230\064" ; 8, 17, 7, 884, 849, "08:17:07.884849", "\057\179\093\161\248\032\221\064" ; 5, 15, 59, 689, 462, "05:15:59.689462", "\117\057\037\032\236\131\210\064" ; 19, 59, 43, 651, 986, "19:59:43.651986", "\055\223\136\110\250\146\241\064" ; 12, 3, 20, 680, 523, "12:03:20.680523", "\166\043\216\198\021\049\229\064" ; 16, 47, 59, 918, 43, "16:47:59.918043", "\170\182\155\096\253\135\237\064" ; 7, 28, 14, 684, 562, "07:28:14.684562", "\134\034\221\207\171\067\218\064" ; 12, 7, 11, 812, 925, "12:07:11.812925", "\035\074\123\003\250\077\229\064" ; 6, 27, 52, 743, 214, "06:27:52.743214", "\251\115\209\144\047\186\214\064" ; 4, 31, 8, 338, 934, "04:31:08.338934", "\192\118\048\098\043\198\207\064" ; 1, 36, 42, 645, 367, "01:36:42.645367", "\235\142\197\054\165\170\182\064" ; 8, 35, 52, 599, 445, "08:35:52.599445", "\176\143\078\093\038\058\222\064" ; 11, 32, 56, 558, 192, "11:32:56.558192", "\028\120\181\220\017\077\228\064" ; 13, 28, 13, 500, 0, "13:28:13.500000", "\000\000\000\000\176\173\231\064" ; 14, 18, 44, 937, 504, "14:18:44.937504", "\124\099\008\000\158\040\233\064" ; 7, 30, 57, 364, 122, "07:30:57.364122", "\113\092\198\077\087\108\218\064" ; 12, 1, 13, 862, 481, "12:01:13.862481", "\014\193\113\153\059\033\229\064" ; 3, 6, 56, 608, 513, "03:06:56.608513", "\025\005\193\227\077\232\197\064" ; 20, 14, 34, 382, 283, "20:14:34.382283", "\109\199\212\029\166\202\241\064" ; 20, 38, 12, 369, 620, "20:38:12.369620", "\064\169\246\233\069\035\242\064" ; 4, 42, 39, 106, 462, "04:42:39.106462", "\017\254\069\208\198\143\208\064" ; 3, 50, 49, 208, 226, "03:50:49.208226", "\023\074\038\167\154\012\203\064" ; 2, 2, 59, 765, 847, "02:02:59.765847", "\190\138\140\014\196\211\188\064" ; 4, 52, 23, 945, 574, "04:52:23.945574", "\125\207\072\132\252\033\209\064" ; 13, 12, 6, 315, 86, "13:12:06.315086", "\046\060\047\021\202\052\231\064" ; 12, 38, 8, 239, 782, "12:38:08.239782", "\006\077\075\172\007\054\230\064" ; 10, 31, 5, 446, 530, "10:31:05.446530", "\086\072\249\073\046\125\226\064" ; 21, 19, 2, 128, 738, "21:19:02.128738", "\188\147\079\015\098\188\242\064" ; 6, 0, 51, 301, 379, "06:00:51.301379", "\045\037\203\073\211\036\213\064" ; 13, 10, 22, 705, 367, "13:10:22.705367", "\150\208\093\146\214\039\231\064" ; 2, 53, 27, 963, 258, "02:53:27.963258", "\206\195\009\076\251\083\196\064" ; 4, 57, 40, 585, 670, "04:57:40.585670", "\016\006\158\123\037\113\209\064" ; 15, 48, 30, 852, 789, "15:48:30.852789", "\044\040\012\074\219\201\235\064" ; 19, 25, 7, 145, 679, "19:25:07.145679", "\204\128\179\084\050\017\241\064" ; 2, 2, 28, 101, 792, "02:02:28.101792", "\254\094\010\015\026\180\188\064" ; 18, 27, 8, 640, 392, "18:27:08.640392", "\138\174\011\063\202\055\240\064" ; 20, 58, 25, 484, 600, "20:58:25.484600", "\250\237\235\192\023\111\242\064" ; 5, 48, 15, 728, 484, "05:48:15.728484", "\234\090\123\159\238\103\212\064" ; 6, 9, 16, 106, 678, "06:09:16.106678", "\077\246\207\211\006\163\213\064" ; 4, 49, 40, 952, 823, "04:49:40.952823", "\248\081\013\251\060\249\208\064" ; 10, 2, 50, 839, 803, "10:02:50.839803", "\131\138\170\223\090\169\225\064" ; 14, 5, 8, 472, 572, "14:05:08.472572", "\160\080\079\031\143\194\232\064" ; 16, 6, 49, 327, 697, "16:06:49.327697", "\064\107\126\124\042\083\236\064" ; 20, 51, 52, 29, 545, "20:51:52.029545", "\140\045\004\121\128\086\242\064" ; 5, 32, 9, 656, 772, "05:32:09.656772", "\059\109\141\008\106\118\211\064" ; 0, 17, 41, 9, 785, "00:17:41.009785", "\247\059\020\005\010\148\144\064" ; 1, 49, 19, 630, 324, "01:49:19.630324", "\226\229\233\092\161\159\185\064" ; 19, 55, 9, 610, 137, "19:55:09.610137", "\209\003\031\195\217\129\241\064" ; 12, 54, 56, 599, 321, "12:54:56.599321", "\218\059\163\045\019\180\230\064" ; 12, 23, 31, 369, 869, "12:23:31.369869", "\090\131\247\213\107\200\229\064" ; 15, 26, 7, 526, 114, "15:26:07.526114", "\255\006\237\213\240\033\235\064" ; 11, 30, 44, 766, 31, "11:30:44.766031", "\152\113\083\131\152\060\228\064" ; 3, 38, 35, 785, 560, "03:38:35.785560", "\134\230\058\141\228\157\201\064" ; 16, 38, 54, 956, 675, "16:38:54.956675", "\189\227\020\157\222\067\237\064" ; 23, 12, 58, 480, 470, "23:12:58.480470", "\139\079\001\176\167\103\244\064" ; 5, 45, 26, 337, 751, "05:45:26.337751", "\204\094\182\157\149\061\212\064" ; 19, 35, 14, 712, 514, "19:35:14.712514", "\127\020\117\102\043\055\241\064" ; 2, 24, 53, 19, 677, "02:24:53.019677", "\190\163\198\132\130\250\192\064" ; 19, 18, 24, 992, 543, "19:18:24.992543", "\206\196\116\225\015\248\240\064" ; 16, 28, 21, 655, 14, "16:28:21.655014", "\141\235\223\245\180\244\236\064" ; 16, 17, 18, 110, 954, "16:17:18.110954", "\044\103\239\140\195\161\236\064" ; 22, 50, 11, 55, 87, "22:50:11.055087", "\246\231\162\225\048\018\244\064" ; 2, 51, 1, 373, 944, "02:51:01.373944", "\068\161\101\221\175\010\196\064" ; 20, 36, 23, 946, 728, "20:36:23.946728", "\099\066\204\037\127\028\242\064" ; 16, 57, 43, 556, 706, "16:57:43.556706", "\239\025\137\208\241\208\237\064" ; 15, 6, 21, 5, 764, "15:06:21.005764", "\239\251\055\047\160\141\234\064" ; 8, 15, 25, 720, 203, "08:15:25.720203", "\223\082\206\023\110\007\221\064" ; 2, 43, 45, 268, 249, "02:43:45.268249", "\024\181\251\085\162\048\195\064" ; 20, 8, 22, 157, 709, "20:08:22.157709", "\085\223\249\133\098\179\241\064" ; 15, 33, 45, 886, 719, "15:33:45.886719", "\056\134\000\096\060\091\235\064" ; 23, 29, 38, 169, 670, "23:29:38.169670", "\209\227\247\182\034\166\244\064" ; 9, 0, 33, 399, 69, "09:00:33.399069", "\247\179\088\138\089\172\223\064" ; 0, 33, 5, 197, 429, "00:33:05.197429", "\032\233\211\042\202\004\159\064" ; 3, 17, 20, 935, 446, "03:17:20.935446", "\150\204\177\188\119\032\199\064" ; 18, 30, 32, 705, 670, "18:30:32.705670", "\060\160\108\074\139\068\240\064" ; 7, 35, 33, 571, 607, "07:35:33.571607", "\203\134\053\149\100\177\218\064" ; 10, 55, 12, 617, 560, "10:55:12.617560", "\106\048\013\195\019\050\227\064" ; 14, 12, 13, 975, 146, "14:12:13.975146", "\090\098\101\052\191\247\232\064" ; 22, 37, 26, 833, 618, "22:37:26.833618", "\246\211\127\086\109\226\243\064" ; 14, 35, 47, 942, 438, "14:35:47.942438", "\145\188\115\040\126\168\233\064" ; 12, 30, 27, 266, 633, "12:30:27.266633", "\226\237\065\136\104\252\229\064" ; 0, 55, 6, 602, 257, "00:55:06.602257", "\147\141\007\091\052\213\169\064" ; 17, 42, 41, 855, 436, "17:42:41.855436", "\123\081\187\095\059\034\239\064" ; 6, 34, 33, 127, 117, "06:34:33.127117", "\113\087\175\034\072\030\215\064" ; 23, 42, 20, 269, 732, "23:42:20.269732", "\107\128\210\080\196\213\244\064" ; 10, 45, 17, 318, 958, "10:45:17.318958", "\089\104\231\052\170\231\226\064" ; 7, 45, 24, 205, 161, "07:45:24.205161", "\091\154\091\033\013\069\219\064" ; 20, 23, 2, 880, 574, "20:23:02.880574", "\060\195\212\022\110\234\241\064" ; 11, 16, 46, 200, 971, "11:16:46.200971", "\014\188\090\110\198\211\227\064" ; 22, 18, 44, 483, 563, "22:18:44.483563", "\104\142\172\188\071\156\243\064" ; 21, 31, 59, 235, 663, "21:31:59.235663", "\222\144\070\197\243\236\242\064" ; 23, 44, 20, 119, 453, "23:44:20.119453", "\135\140\071\233\065\221\244\064" ; 1, 47, 14, 909, 624, "01:47:14.909624", "\168\083\030\221\232\034\185\064" ; 11, 42, 56, 333, 948, "11:42:56.333948", "\082\183\179\175\010\152\228\064" ; 10, 11, 29, 667, 782, "10:11:29.667782", "\092\091\120\094\053\234\225\064" ; 16, 5, 44, 965, 101, "16:05:44.965101", "\010\126\027\226\030\075\236\064" ; 14, 10, 22, 872, 90, "14:10:22.872090", "\166\073\041\232\219\233\232\064" ; 15, 7, 55, 130, 367, "15:07:55.130367", "\047\106\247\043\100\153\234\064" ; 4, 37, 16, 47, 359, "04:37:16.047359", "\011\011\238\007\003\063\208\064" ; 2, 59, 56, 344, 489, "02:59:56.344489", "\106\046\055\024\044\022\197\064" ; 8, 53, 42, 853, 836, "08:53:42.853836", "\009\192\063\165\182\069\223\064" ; 16, 12, 24, 692, 116, "16:12:24.692116", "\034\116\208\037\022\125\236\064" ; 15, 27, 1, 153, 184, "15:27:01.153184", "\200\033\226\230\164\040\235\064" ; 8, 52, 45, 117, 285, "08:52:45.117285", "\211\241\152\129\071\055\223\064" ; 19, 31, 36, 882, 686, "19:31:36.882686", "\234\090\123\031\142\041\241\064" ; 22, 11, 2, 79, 653, "22:11:02.079653", "\096\057\066\070\097\127\243\064" ; 11, 20, 17, 61, 448, "11:20:17.061448", "\205\203\097\247\033\238\227\064" ; 12, 51, 13, 265, 812, "12:51:13.265812", "\220\042\136\129\040\152\230\064" ; 8, 53, 41, 398, 173, "08:53:41.398173", "\074\155\170\123\089\069\223\064" ; 0, 41, 38, 75, 595, "00:41:38.075595", "\123\073\099\180\038\132\163\064" ; 17, 4, 29, 669, 129, "17:04:29.669129", "\122\056\129\105\181\003\238\064" ; 20, 16, 41, 587, 842, "20:16:41.587842", "\083\003\205\103\153\210\241\064" ; 10, 2, 7, 555, 184, "10:02:07.555184", "\104\060\017\196\241\163\225\064" ; 5, 2, 48, 880, 368, "05:02:48.880368", "\029\006\243\087\056\190\209\064" ; 19, 3, 43, 90, 675, "19:03:43.090675", "\249\160\103\115\241\192\240\064" ; 16, 59, 29, 159, 794, "16:59:29.159794", "\131\078\008\029\037\222\237\064" ; 15, 40, 43, 393, 701, "15:40:43.393701", "\236\214\050\153\108\143\235\064" ; 12, 25, 56, 731, 148, "12:25:56.731148", "\145\125\144\101\151\218\229\064" ; 8, 50, 21, 814, 342, "08:50:21.814342", "\112\232\045\030\116\019\223\064" ; 9, 23, 38, 480, 894, "09:23:38.480894", "\091\208\123\099\079\131\224\064" ; 8, 14, 44, 822, 398, "08:14:44.822398", "\147\056\043\162\052\253\220\064" ; 7, 25, 57, 709, 854, "07:25:57.709854", "\188\120\063\110\109\033\218\064" ; 2, 54, 28, 763, 957, "02:54:28.763957", "\071\205\087\201\097\114\196\064" ; 23, 36, 18, 536, 644, "23:36:18.536644", "\217\004\024\150\040\191\244\064" ; 4, 56, 48, 660, 319, "04:56:48.660319", "\123\159\170\066\042\100\209\064" ; 15, 54, 29, 56, 761, "15:54:29.056761", "\214\113\252\208\161\246\235\064" ; 11, 48, 57, 795, 554, "11:48:57.795554", "\134\169\045\117\057\197\228\064" ; 22, 39, 19, 879, 168, "22:39:19.879168", "\251\118\018\017\126\233\243\064" ; 0, 55, 6, 919, 48, "00:55:06.919048", "\232\158\117\141\214\213\169\064" ; 6, 53, 10, 859, 696, "06:53:10.859696", "\032\095\066\005\183\053\216\064" ; 2, 20, 40, 946, 344, "02:20:40.946344", "\098\217\204\033\121\124\192\064" ; 20, 16, 36, 258, 410, "20:16:36.258410", "\047\134\114\034\068\210\241\064" ; 15, 25, 56, 413, 947, "15:25:56.413947", "\105\199\013\063\141\032\235\064" ; 8, 54, 31, 397, 433, "08:54:31.397433", "\087\210\138\111\217\081\223\064" ; 7, 33, 19, 443, 782, "07:33:19.443782", "\035\158\236\102\220\143\218\064" ; 16, 4, 50, 598, 122, "16:04:50.598122", "\160\191\208\035\083\068\236\064" ; 11, 23, 23, 824, 343, "11:23:23.824343", "\054\146\004\097\122\005\228\064" ; 17, 42, 27, 266, 899, "17:42:27.266899", "\139\197\111\138\104\032\239\064" ; 19, 45, 20, 907, 68, "19:45:20.907068", "\052\188\089\131\014\093\241\064" ; 19, 4, 6, 719, 946, "19:04:06.719946", "\206\024\230\132\107\194\240\064" ; 5, 56, 18, 701, 573, "05:56:18.701573", "\177\112\146\230\172\224\212\064" ; 16, 52, 26, 116, 339, "16:52:26.116339", "\008\145\012\185\067\169\237\064" ; 1, 25, 49, 348, 144, "01:25:49.348144", "\076\022\247\031\089\029\180\064" ; 5, 40, 36, 285, 873, "05:40:36.285873", "\116\068\190\075\018\245\211\064" ; 1, 8, 27, 436, 60, "01:08:27.436060", "\024\207\160\161\111\011\176\064" ; 12, 19, 7, 143, 447, "12:19:07.143447", "\182\041\030\151\100\167\229\064" ; 2, 31, 45, 802, 178, "02:31:45.802178", "\201\201\196\173\230\200\193\064" ; 4, 8, 47, 439, 38, "04:08:47.439038", "\218\173\101\050\184\039\205\064" ; 14, 39, 22, 321, 355, "14:39:22.321355", "\237\071\138\072\074\195\233\064" ; 12, 56, 8, 71, 799, "12:56:08.071799", "\157\106\045\076\002\189\230\064" ; 1, 19, 20, 794, 172, "01:19:20.794172", "\102\047\219\078\203\152\178\064" ; 22, 14, 42, 340, 453, "22:14:42.340453", "\077\216\126\114\037\141\243\064" ; 0, 37, 14, 434, 214, "00:37:14.434214", "\239\034\076\081\222\116\161\064" ; 3, 39, 21, 951, 474, "03:39:21.951474", "\127\104\230\201\249\180\201\064" ; 5, 47, 55, 273, 302, "05:47:55.273302", "\252\171\199\125\209\098\212\064" ; 14, 58, 24, 121, 693, "14:58:24.121693", "\229\183\232\228\003\082\234\064" ; 10, 59, 25, 202, 866, "10:59:25.202866", "\111\214\224\125\166\081\227\064" ; 13, 6, 47, 190, 937, "13:06:47.190937", "\083\233\039\028\230\012\231\064" ; 17, 3, 55, 248, 809, "17:03:55.248809", "\190\074\062\246\103\255\237\064" ; 15, 40, 50, 405, 21, "15:40:50.405021", "\166\153\238\245\076\144\235\064" ; 5, 30, 32, 644, 730, "05:30:32.644730", "\048\158\065\067\041\094\211\064" ; 17, 42, 22, 510, 510, "17:42:22.510510", "\073\017\025\086\208\031\239\064" ; 16, 6, 49, 132, 384, "16:06:49.132384", "\208\094\125\060\036\083\236\064" ; 4, 27, 59, 995, 150, "04:27:59.995150", "\079\064\019\097\255\103\207\064" ; 13, 48, 56, 799, 426, "13:48:56.799426", "\178\213\229\148\025\073\232\064" ; 18, 3, 17, 764, 503, "18:03:17.764503", "\215\254\206\118\184\188\239\064" ; 11, 41, 4, 108, 342, "11:41:04.108342", "\089\164\137\119\003\138\228\064" ; 10, 34, 53, 35, 301, "10:34:53.035301", "\017\144\047\033\161\153\226\064" ; 9, 31, 0, 208, 603, "09:31:00.208603", "\219\050\224\172\134\186\224\064" ; 14, 39, 22, 564, 414, "14:39:22.564414", "\237\242\173\015\082\195\233\064" ; 20, 43, 30, 142, 732, "20:43:30.142732", "\130\089\161\072\034\055\242\064" ; 1, 12, 43, 604, 295, "01:12:43.604295", "\035\190\019\179\154\011\177\064" ; 19, 21, 28, 404, 444, "19:21:28.404444", "\145\069\154\120\134\003\241\064" ; 22, 23, 58, 876, 627, "22:23:58.876627", "\125\008\170\006\238\175\243\064" ; 17, 49, 19, 616, 719, "17:49:19.616719", "\251\123\041\188\243\083\239\064" ; 3, 12, 52, 161, 218, "03:12:52.161218", "\195\154\202\162\020\154\198\064" ; 9, 44, 4, 715, 239, "09:44:04.715239", "\058\230\060\227\150\028\225\064" ; 22, 9, 51, 587, 469, "22:09:51.587469", "\231\228\069\102\249\122\243\064" ; 3, 17, 25, 440, 891, "03:17:25.440891", "\013\197\029\111\184\034\199\064" ; 20, 56, 13, 739, 245, "20:56:13.739245", "\172\144\242\211\219\102\242\064" ; 1, 23, 48, 248, 400, "01:23:48.248400", "\083\116\036\151\063\164\179\064" ; 21, 20, 20, 678, 10, "21:20:20.678010", "\134\003\033\217\074\193\242\064" ; 13, 4, 13, 459, 39, "13:04:13.459039", "\147\142\114\176\174\249\230\064" ; 15, 51, 0, 925, 434, "15:51:00.925434", "\148\195\039\157\157\220\235\064" ; 15, 37, 23, 438, 773, "15:37:23.438773", "\172\172\109\010\110\118\235\064" ; 18, 10, 35, 978, 738, "18:10:35.978738", "\172\090\210\081\127\243\239\064" ; 4, 7, 0, 376, 685, "04:07:00.376685", "\243\205\054\055\048\242\204\064" ; 16, 31, 4, 384, 233, "16:31:04.384233", "\033\001\163\075\012\009\237\064" ; 4, 49, 44, 645, 28, "04:49:44.645028", "\064\133\035\072\041\250\208\064" ; 2, 17, 3, 14, 485, "02:17:03.014485", "\164\252\164\218\129\015\192\064" ; 7, 43, 7, 263, 872, "07:43:07.263872", "\149\098\071\227\208\034\219\064" ; 15, 36, 51, 533, 429, "15:36:51.533429", "\184\177\217\017\113\114\235\064" ; 4, 7, 2, 593, 282, "04:07:02.593282", "\168\033\170\240\075\243\204\064" ; 4, 4, 35, 644, 36, "04:04:35.644036", "\185\138\197\111\210\169\204\064" ; 0, 7, 19, 125, 774, "00:07:19.125774", "\254\010\153\043\003\114\123\064" ; 12, 21, 40, 723, 786, "12:21:40.723786", "\233\065\065\041\151\186\229\064" ; 2, 50, 19, 32, 900, "02:50:19.032900", "\004\052\017\054\132\245\195\064" ; 4, 9, 39, 393, 872, "04:09:39.393872", "\104\207\101\106\178\065\205\064" ; 21, 29, 14, 499, 936, "21:29:14.499936", "\033\228\188\255\167\226\242\064" ; 23, 31, 57, 897, 446, "23:31:57.897446", "\063\086\240\091\222\174\244\064" ; 15, 21, 44, 334, 296, "15:21:44.334296", "\102\134\141\178\010\001\235\064" ; 9, 36, 19, 347, 516, "09:36:19.347516", "\219\223\217\030\107\226\224\064" ; 12, 8, 23, 489, 725, "12:08:23.489725", "\097\195\211\171\239\086\229\064" ; 3, 4, 53, 253, 386, "03:04:53.253386", "\162\211\243\110\160\170\197\064" ; 12, 32, 8, 793, 237, "12:32:08.793237", "\159\143\050\098\025\009\230\064" ; 8, 38, 52, 895, 677, "08:38:52.895677", "\178\159\197\082\057\103\222\064" ; 17, 33, 23, 586, 449, "17:33:23.586449", "\121\177\048\196\114\220\238\064" ; 11, 19, 45, 211, 808, "11:19:45.211808", "\033\146\033\199\038\234\227\064" ; 1, 35, 37, 733, 267, "01:35:37.733267", "\061\216\098\183\187\105\182\064" ; 18, 34, 34, 321, 679, "18:34:34.321679", "\013\225\152\037\165\083\240\064" ; 22, 4, 15, 895, 696, "22:04:15.895696", "\051\084\197\084\254\101\243\064" ; 20, 8, 38, 887, 921, "20:08:38.887921", "\135\166\236\052\110\180\241\064" ; 10, 9, 39, 66, 50, "10:09:39.066050", "\189\227\020\029\098\220\225\064" ; 0, 21, 15, 368, 733, "00:21:15.368733", "\211\191\036\149\121\237\147\064" ; 10, 49, 48, 879, 259, "10:49:48.879259", "\055\197\227\034\156\009\227\064" ; 5, 18, 31, 782, 90, "05:18:31.782090", "\034\055\195\013\242\169\210\064" ; 10, 43, 13, 717, 920, "10:43:13.717920", "\036\093\051\249\054\216\226\064" ; 23, 29, 32, 482, 613, "23:29:32.482613", "\186\104\200\184\199\165\244\064" ; 21, 42, 42, 711, 504, "21:42:42.711504", "\175\004\082\098\043\021\243\064" ; 3, 46, 39, 652, 685, "03:46:39.652685", "\204\156\046\139\211\143\202\064" ; 19, 7, 35, 154, 868, "19:07:35.154868", "\051\222\086\122\114\207\240\064" ; 4, 30, 59, 920, 675, "04:30:59.920675", "\159\171\173\216\245\193\207\064" ; 23, 56, 1, 138, 724, "23:56:01.138724", "\051\168\054\056\018\009\245\064" ; 8, 4, 11, 326, 324, "08:04:11.326324", "\250\014\126\226\212\094\220\064" ; 10, 21, 3, 877, 764, "10:21:03.877764", "\051\135\164\022\252\049\226\064" ; 4, 54, 50, 386, 684, "04:54:50.386684", "\120\063\110\191\152\070\209\064" ; 1, 43, 24, 292, 326, "01:43:24.292326", "\198\113\224\213\074\060\184\064" ; 16, 30, 39, 529, 403, "16:30:39.529403", "\109\143\222\240\240\005\237\064" ; 18, 0, 7, 423, 130, "18:00:07.423130", "\255\236\071\138\237\164\239\064" ; 18, 33, 40, 852, 898, "18:33:40.852898", "\141\095\120\165\077\080\240\064" ; 1, 21, 58, 521, 303, "01:21:58.521303", "\078\008\029\116\133\054\179\064" ; 6, 16, 10, 174, 730, "06:16:10.174730", "\232\188\198\046\139\010\214\064" ; 5, 21, 21, 67, 309, "05:21:21.067309", "\110\104\202\078\068\212\210\064" ; 19, 29, 42, 513, 411, "19:29:42.513411", "\231\115\238\054\104\034\241\064" ; 0, 33, 36, 832, 540, "00:33:36.832540", "\115\162\093\133\084\131\159\064" ; 16, 23, 11, 816, 67, "16:23:11.816067", "\139\138\056\029\250\205\236\064" ; 19, 47, 33, 881, 989, "19:47:33.881989", "\102\127\160\028\094\101\241\064" ; 15, 28, 55, 767, 173, "15:28:55.767173", "\044\100\174\140\248\054\235\064" ; 1, 7, 13, 67, 142, "01:07:13.067142", "\096\172\111\096\034\130\175\064" ; 15, 17, 47, 157, 626, "15:17:47.157626", "\096\174\069\011\101\227\234\064" ; 8, 20, 7, 429, 942, "08:20:07.429942", "\075\115\043\132\219\077\221\064" ; 3, 23, 49, 197, 245, "03:23:49.197245", "\038\252\082\063\153\226\199\064" ; 11, 57, 18, 295, 634, "11:57:18.295634", "\051\111\213\117\201\003\229\064" ; 22, 21, 30, 958, 588, "22:21:30.958588", "\229\094\096\086\175\166\243\064" ; 13, 46, 23, 939, 754, "13:46:23.939754", "\009\251\118\018\254\053\232\064" ; 21, 4, 17, 481, 697, "21:04:17.481697", "\217\233\007\181\023\133\242\064" ; 8, 13, 15, 630, 16, "08:13:15.630016", "\254\160\046\082\232\230\220\064" ; 3, 20, 59, 274, 476, "03:20:59.274476", "\196\145\007\034\163\141\199\064" ; 0, 39, 6, 278, 220, "00:39:06.278220", "\047\018\218\114\142\084\162\064" ; 22, 31, 53, 612, 111, "22:31:53.612111", "\104\231\052\203\153\205\243\064" ; 21, 5, 31, 48, 145, "21:05:31.048145", "\007\177\051\197\176\137\242\064" ; 14, 5, 31, 181, 783, "14:05:31.181783", "\255\148\042\209\101\197\232\064" ; 5, 27, 38, 500, 686, "05:27:38.500686", "\228\074\061\011\160\050\211\064" ; 13, 15, 53, 903, 245, "13:15:53.903245", "\233\014\098\231\060\081\231\064" ; 18, 8, 33, 283, 141, "18:08:33.283141", "\229\182\125\015\041\228\239\064" ; 1, 9, 14, 864, 223, "01:09:14.864223", "\115\241\183\061\221\058\176\064" ; 1, 17, 17, 155, 481, "01:17:17.155481", "\038\082\154\205\039\029\178\064" ; 10, 51, 32, 550, 823, "10:51:32.550823", "\093\142\087\160\145\022\227\064" ; 23, 22, 48, 390, 395, "23:22:48.390395", "\216\211\014\063\134\140\244\064" ; 6, 47, 50, 561, 849, "06:47:50.561849", "\019\130\085\245\163\229\215\064" ; 3, 9, 11, 691, 80, "03:09:11.691080", "\118\055\079\117\216\043\198\064" ; 19, 3, 53, 666, 463, "19:03:53.666463", "\080\027\213\169\154\193\240\064" ; 3, 7, 5, 405, 517, "03:07:05.405517", "\125\038\251\231\179\236\197\064" ; 20, 47, 8, 161, 714, "20:47:08.161714", "\084\107\097\150\194\068\242\064" ; 4, 25, 16, 590, 556, "04:25:16.590556", "\059\201\086\151\075\022\207\064" ; 14, 30, 8, 211, 905, "14:30:08.211905", "\156\254\236\199\006\126\233\064" ; 18, 46, 22, 279, 241, "18:46:22.279241", "\043\105\197\119\228\127\240\064" ; 21, 8, 2, 878, 577, "21:08:02.878577", "\160\193\166\014\046\147\242\064" ; 8, 44, 20, 855, 369, "08:44:20.855369", "\065\158\093\190\054\185\222\064" ; 12, 46, 8, 690, 128, "12:46:08.690128", "\194\080\135\021\022\114\230\064" ; 5, 18, 20, 84, 571, "05:18:20.084571", "\204\123\156\105\005\167\210\064" ; 13, 33, 5, 366, 678, "13:33:05.366678", "\069\128\211\187\043\210\231\064" ; 5, 42, 44, 966, 847, "05:42:44.966847", "\079\061\210\224\061\021\212\064" ; 19, 5, 46, 812, 741, "19:05:46.812741", "\242\180\252\000\173\200\240\064" ; 0, 13, 36, 597, 239, "00:13:36.597239", "\042\167\061\037\199\132\137\064" ; 17, 14, 23, 650, 198, "17:14:23.650198", "\062\009\108\206\244\077\238\064" ; 11, 22, 43, 782, 331, "11:22:43.782331", "\117\005\219\008\121\000\228\064" ; 11, 10, 0, 168, 441, "11:10:00.168441", "\073\097\222\099\005\161\227\064" ; 12, 39, 21, 573, 241, "12:39:21.573241", "\119\130\253\087\050\063\230\064" ; 2, 11, 8, 424, 906, "02:11:08.424906", "\224\189\163\198\108\188\190\064" ; 21, 13, 28, 559, 638, "21:13:28.559638", "\185\249\070\244\136\167\242\064" ; 10, 4, 6, 666, 360, "10:04:06.666360", "\235\052\210\082\213\178\225\064" ; 8, 7, 54, 509, 807, "08:07:54.509807", "\017\138\173\160\160\150\220\064" ; 16, 4, 57, 273, 105, "16:04:57.273105", "\108\178\070\189\040\069\236\064" ; 3, 3, 15, 248, 154, "03:03:15.248154", "\047\161\130\195\159\121\197\064" ; 6, 29, 38, 281, 64, "06:29:38.281064", "\005\220\243\252\145\212\214\064" ; 21, 15, 59, 794, 329, "21:15:59.794329", "\084\083\146\181\252\176\242\064" ; 9, 21, 31, 529, 476, "09:21:31.529476", "\001\167\119\241\112\115\224\064" ; 6, 15, 45, 342, 434, "06:15:45.342434", "\195\075\112\234\085\004\214\064" ; 18, 33, 48, 178, 263, "18:33:48.178263", "\177\077\042\218\194\080\240\064" ; 20, 32, 16, 218, 503, "20:32:16.218503", "\113\000\253\126\003\013\242\064" ; 18, 41, 28, 234, 629, "18:41:28.234629", "\155\086\010\193\131\109\240\064" ; 11, 26, 37, 816, 405, "11:26:37.816405", "\233\096\253\031\186\029\228\064" ; 7, 22, 9, 35, 17, "07:22:09.035017", "\115\241\183\061\066\232\217\064" ; 4, 13, 22, 968, 11, "04:13:22.968011", "\150\209\200\231\123\177\205\064" ; 8, 9, 2, 202, 49, "08:09:02.202049", "\204\237\094\238\140\167\220\064" ; 11, 13, 22, 524, 907, "11:13:22.524907", "\206\195\009\204\080\186\227\064" ; 2, 57, 46, 946, 126, "02:57:46.946126", "\243\033\168\026\121\213\196\064" ; 8, 7, 22, 176, 902, "08:07:22.176902", "\038\196\092\082\139\142\220\064" ; 12, 12, 43, 767, 319, "12:12:43.767319", "\083\147\224\141\120\119\229\064" ; 14, 11, 54, 504, 883, "14:11:54.504883", "\170\100\000\040\080\245\232\064" ; 3, 27, 53, 516, 793, "03:27:53.516793", "\230\228\069\038\194\092\200\064" ; 10, 13, 29, 410, 433, "10:13:29.410433", "\007\099\068\034\045\249\225\064" ; 17, 56, 16, 657, 693, "17:56:16.657693", "\186\048\210\011\021\136\239\064" ; 20, 51, 1, 454, 394, "20:51:01.454394", "\152\164\050\069\087\083\242\064" ; 18, 26, 39, 9, 422, "18:26:39.009422", "\222\174\151\038\240\053\240\064" ; 15, 58, 41, 484, 152, "15:58:41.484152", "\201\085\044\126\047\022\236\064" ; 16, 40, 5, 222, 300, "16:40:05.222300", "\189\227\020\029\167\076\237\064" ; 5, 17, 1, 689, 457, "05:17:01.689457", "\191\064\016\032\108\147\210\064" ; 3, 8, 47, 346, 86, "03:08:47.346086", "\205\201\139\076\172\031\198\064" ; 8, 32, 37, 932, 793, "08:32:37.932793", "\060\105\225\178\123\009\222\064" ; 9, 39, 49, 44, 365, "09:39:49.044365", "\003\038\112\107\161\252\224\064" ; 4, 22, 35, 273, 545, "04:22:35.273545", "\126\198\133\003\163\197\206\064" ; 12, 35, 42, 348, 465, "12:35:42.348465", "\089\018\160\038\203\035\230\064" ; 9, 57, 23, 362, 840, "09:57:23.362840", "\182\161\098\156\107\128\225\064" ; 17, 49, 16, 484, 536, "17:49:16.484536", "\055\164\081\129\143\083\239\064" ; 21, 10, 27, 271, 143, "21:10:27.271143", "\216\010\154\086\052\156\242\064" ; 23, 54, 53, 784, 922, "23:54:53.784922", "\255\094\010\143\220\004\245\064" ; 8, 15, 23, 160, 485, "08:15:23.160485", "\160\224\098\069\202\006\221\064" ; 9, 27, 57, 281, 770, "09:27:57.281770", "\224\132\066\004\169\163\224\064" ; 23, 35, 55, 505, 113, "23:35:55.505113", "\125\094\241\020\184\189\244\064" ; 18, 41, 31, 266, 293, "18:41:31.266293", "\227\114\188\066\180\109\240\064" ; 7, 12, 26, 167, 460, "07:12:26.167460", "\217\037\170\183\138\086\217\064" ; 13, 3, 31, 964, 162, "13:03:31.964162", "\065\068\106\218\126\244\230\064" ; 15, 11, 47, 306, 987, "15:11:47.306987", "\169\102\214\210\105\182\234\064" ; 16, 39, 23, 177, 168, "16:39:23.177168", "\189\057\092\171\101\071\237\064" ; 0, 55, 32, 673, 674, "00:55:32.673674", "\084\108\204\235\088\009\170\064" ; 2, 23, 9, 331, 232, "02:23:09.331232", "\178\103\207\101\170\198\192\064" ; 10, 19, 13, 25, 994, "10:19:13.025994", "\125\094\241\212\032\036\226\064" ; 7, 55, 16, 748, 129, "07:55:16.748129", "\012\117\088\225\047\217\219\064" ; 21, 46, 13, 576, 597, "21:46:13.576597", "\160\198\189\057\089\034\243\064" ; 22, 4, 13, 209, 673, "22:04:13.209673", "\094\019\210\090\211\101\243\064" ; 16, 46, 14, 744, 595, "16:46:14.744595", "\184\228\184\211\215\122\237\064" ; 7, 47, 43, 344, 345, "07:47:43.344345", "\099\156\191\009\214\103\219\064" ; 14, 5, 42, 988, 670, "14:05:42.988670", "\145\068\047\163\223\198\232\064" ; 0, 0, 19, 673, 691, "00:00:19.673691", "\011\156\108\003\119\172\051\064" ; 23, 56, 5, 798, 286, "23:56:05.798286", "\109\138\199\197\092\009\245\064" ; 11, 41, 48, 117, 110, "11:41:48.117110", "\129\120\093\191\131\143\228\064" ; 15, 11, 34, 676, 889, "15:11:34.676889", "\193\030\019\169\213\180\234\064" ; 23, 50, 43, 238, 895, "23:50:43.238895", "\067\144\131\210\051\245\244\064" ; 9, 25, 4, 851, 958, "09:25:04.851958", "\114\108\061\067\027\142\224\064" ; 19, 59, 46, 445, 190, "19:59:46.445190", "\169\140\127\031\039\147\241\064" ; 4, 2, 21, 381, 556, "04:02:21.381556", "\204\182\211\214\176\102\204\064" ; 13, 37, 21, 47, 342, "13:37:21.047342", "\183\094\211\131\033\242\231\064" ; 12, 11, 56, 194, 33, "12:11:56.194033", "\171\177\132\053\134\113\229\064" ; 14, 59, 30, 356, 10, "14:59:30.356010", "\098\021\111\100\075\090\234\064" ; 20, 35, 37, 307, 355, "20:35:37.307355", "\148\019\237\234\148\025\242\064" ; 4, 38, 16, 505, 414, "04:38:16.505414", "\060\246\179\088\032\078\208\064" ; 9, 36, 22, 936, 441, "09:36:22.936441", "\180\029\083\247\221\226\224\064" ; 0, 11, 30, 420, 468, "00:11:30.420468", "\029\168\083\030\093\147\133\064" ; 0, 49, 16, 416, 330, "00:49:16.416330", "\176\172\052\041\213\024\167\064" ; 15, 57, 11, 33, 955, "15:57:11.033955", "\210\203\040\022\225\010\236\064" ; 4, 14, 27, 938, 185, "04:14:27.938185", "\077\050\114\022\248\209\205\064" ; 16, 8, 10, 8, 528, "16:08:10.008528", "\035\131\220\069\064\093\236\064" ; 3, 4, 54, 239, 196, "03:04:54.239196", "\171\122\249\157\030\171\197\064" ; 2, 40, 42, 61, 158, "02:40:42.061158", "\242\124\006\212\007\213\194\064" ; 1, 37, 15, 408, 772, "01:37:15.408772", "\134\035\072\165\104\203\182\064" ; 13, 51, 55, 468, 793, "13:51:55.468793", "\115\045\090\000\111\095\232\064" ; 13, 15, 40, 276, 735, "13:15:40.276735", "\213\091\003\219\136\079\231\064" ; 4, 7, 5, 535, 41, "04:07:05.535041", "\130\054\057\124\196\244\204\064" ; 17, 11, 20, 812, 712, "17:11:20.812712", "\162\152\188\001\026\055\238\064" ; 6, 53, 52, 272, 219, "06:53:52.272219", "\151\061\009\108\017\064\216\064" ; 2, 26, 55, 907, 609, "02:26:55.907609", "\071\030\136\044\244\055\193\064" ; 7, 29, 22, 749, 961, "07:29:22.749961", "\018\108\092\255\175\084\218\064" ; 8, 2, 47, 462, 593, "08:02:47.462593", "\151\171\031\155\221\073\220\064" ; 18, 22, 33, 814, 673, "18:22:33.814673", "\063\142\230\008\157\038\240\064" ; 11, 22, 37, 585, 386, "11:22:37.585386", "\177\107\123\187\178\255\227\064" ; 2, 32, 24, 516, 317, "02:32:24.516317", "\175\234\172\022\066\220\193\064" ; 8, 6, 19, 898, 40, "08:06:19.898040", "\160\195\124\121\249\126\220\064" ; 21, 51, 46, 161, 46, "21:51:46.161046", "\114\248\164\147\034\055\243\064" ; 4, 38, 8, 736, 122, "04:38:08.736122", "\248\114\159\028\047\076\208\064" ; 10, 1, 56, 331, 324, "10:01:56.331324", "\012\202\052\154\138\162\225\064" ; 9, 18, 22, 232, 858, "09:18:22.232858", "\212\158\146\115\199\091\224\064" ; 7, 20, 24, 886, 484, "07:20:24.886484", "\027\099\039\188\056\206\217\064" ; 6, 43, 47, 275, 296, "06:43:47.275296", "\046\029\115\158\209\168\215\064" ; 11, 40, 14, 314, 268, "11:40:14.314268", "\198\195\123\014\202\131\228\064" ; 10, 34, 1, 192, 393, "10:34:01.192393", "\096\093\021\040\038\147\226\064" ; 0, 47, 20, 855, 755, "00:47:20.855755", "\199\244\132\037\182\049\166\064" ; 12, 43, 23, 793, 289, "12:43:23.793289", "\233\156\159\098\121\093\230\064" ; 7, 57, 8, 3, 823, "07:57:08.003823", "\254\210\162\062\000\245\219\064" ; 10, 58, 38, 679, 872, "10:58:38.679872", "\174\236\130\193\213\075\227\064" ; 5, 54, 41, 99, 883, "05:54:41.099883", "\155\170\123\100\070\200\212\064" ; 6, 48, 14, 468, 25, "06:48:14.468025", "\046\033\031\244\157\235\215\064" ; 11, 34, 10, 997, 830, "11:34:10.997830", "\031\046\057\238\095\086\228\064" ; 6, 42, 52, 664, 199, "06:42:52.664199", "\194\133\060\130\042\155\215\064" ; 18, 55, 0, 254, 376, "18:55:00.254376", "\142\145\236\017\068\160\240\064" ; 15, 32, 39, 711, 577, "15:32:39.711577", "\243\032\061\197\246\082\235\064" ; 3, 19, 38, 993, 859, "03:19:38.993859", "\235\142\197\054\127\101\199\064" ; 10, 53, 53, 141, 631, "10:53:53.141631", "\036\188\061\136\036\040\227\064" ; 3, 57, 51, 214, 12, "03:57:51.214012", "\122\198\190\100\155\223\203\064" ; 20, 1, 36, 858, 904, "20:01:36.858904", "\230\030\018\190\013\154\241\064" ; 23, 40, 25, 349, 376, "23:40:25.349376", "\224\073\011\151\149\206\244\064" ; 23, 44, 46, 652, 29, "23:44:46.652029", "\241\245\181\110\234\222\244\064" ; 6, 12, 45, 185, 210, "06:12:45.185210", "\057\011\123\218\075\215\213\064" ; 6, 24, 23, 983, 829, "06:24:23.983829", "\247\232\013\247\254\133\214\064" ; 13, 32, 47, 528, 954, "13:32:47.528954", "\099\240\048\237\240\207\231\064" ; 17, 3, 48, 745, 729, "17:03:48.745729", "\086\016\003\221\151\254\237\064" ; 15, 4, 19, 552, 100, "15:04:19.552100", "\132\158\205\170\113\126\234\064" ; 22, 23, 59, 799, 304, "22:23:59.799304", "\185\253\242\201\252\175\243\064" ; 14, 47, 52, 842, 814, "14:47:52.842814", "\211\016\085\248\026\003\234\064" ; 9, 2, 31, 221, 208, "09:02:31.221208", "\104\153\069\040\206\201\223\064" ; 16, 25, 0, 133, 568, "16:25:00.133568", "\250\101\048\070\132\219\236\064" ; 22, 3, 41, 622, 769, "22:03:41.622769", "\128\160\220\246\217\099\243\064" ; 23, 1, 55, 364, 177, "23:01:55.364177", "\015\067\171\211\053\062\244\064" ; 1, 19, 46, 81, 8, "01:19:46.081008", "\183\182\240\188\020\178\178\064" ; 9, 48, 3, 15, 698, "09:48:03.015698", "\148\023\153\128\096\058\225\064" ; 1, 52, 6, 601, 848, "01:52:06.601848", "\041\229\181\018\154\070\186\064" ; 21, 15, 22, 364, 509, "21:15:22.364509", "\162\099\007\213\165\174\242\064" ; 7, 3, 23, 729, 687, "07:03:23.729687", "\084\026\049\179\238\206\216\064" ; 12, 16, 38, 28, 405, "12:16:38.028405", "\065\154\177\232\192\148\229\064" ; 21, 43, 45, 527, 133, "21:43:45.527133", "\058\003\035\111\024\025\243\064" ; 8, 33, 27, 737, 773, "08:33:27.737773", "\184\062\172\055\239\021\222\064" ; 19, 47, 17, 845, 420, "19:47:17.845420", "\054\031\215\134\093\100\241\064" ; 6, 40, 41, 358, 928, "06:40:41.358928", "\104\037\173\248\086\122\215\064" ; 7, 17, 9, 474, 614, "07:17:09.474614", "\014\102\019\096\094\157\217\064" ; 5, 21, 9, 840, 643, "05:21:09.840643", "\039\076\024\205\117\209\210\064" ; 6, 51, 20, 770, 967, "06:51:20.770967", "\211\248\133\087\049\026\216\064" ; 6, 9, 16, 241, 388, "06:09:16.241388", "\106\167\230\114\015\163\213\064" ; 13, 42, 37, 315, 60, "13:42:37.315060", "\137\181\248\020\170\025\232\064" ; 19, 43, 50, 627, 467, "19:43:50.627467", "\069\214\026\010\106\087\241\064" ; 9, 57, 33, 284, 588, "09:57:33.284588", "\027\075\088\027\169\129\225\064" ; 18, 52, 4, 915, 202, "18:52:04.915202", "\051\218\170\164\078\149\240\064" ; 0, 40, 36, 487, 708, "00:40:36.487708", "\255\235\220\180\249\008\163\064" ; 9, 28, 50, 444, 35, "09:28:50.444035", "\105\227\136\053\078\170\224\064" ; 19, 5, 1, 440, 615, "19:05:01.440615", "\114\080\194\012\215\197\240\064" ; 4, 55, 25, 794, 785, "04:55:25.794785", "\151\231\193\221\114\079\209\064" ; 1, 39, 6, 182, 541, "01:39:06.182541", "\046\201\001\187\046\058\183\064" ; 21, 24, 31, 773, 926, "21:24:31.773926", "\184\058\000\098\252\208\242\064" ; 12, 46, 5, 414, 645, "12:46:05.414645", "\078\151\197\068\173\113\230\064" ; 16, 17, 25, 435, 599, "16:17:25.435599", "\101\080\109\240\173\162\236\064" ; 9, 54, 49, 823, 684, "09:54:49.823684", "\071\140\158\091\058\109\225\064" ; 16, 48, 37, 978, 598, "16:48:37.978598", "\190\192\172\080\191\140\237\064" ; 11, 54, 50, 488, 509, "11:54:50.488509", "\089\160\221\161\079\241\228\064" ; 15, 12, 39, 655, 77, "15:12:39.655077", "\107\010\100\246\244\188\234\064" ; 12, 8, 11, 983, 809, "12:08:11.983809", "\016\003\093\123\127\085\229\064" ; 23, 0, 3, 737, 920, "23:00:03.737920", "\177\051\133\206\059\055\244\064" ; 13, 56, 27, 161, 913, "13:56:27.161913", "\250\043\100\046\101\129\232\064" ; 14, 39, 2, 49, 534, "14:39:02.049534", "\193\083\200\149\193\192\233\064" ; 20, 30, 42, 585, 901, "20:30:42.585901", "\028\186\217\095\041\007\242\064" ; 18, 29, 17, 557, 588, "18:29:17.557588", "\010\101\225\235\216\063\240\064" ; 15, 4, 3, 693, 142, "15:04:03.693142", "\175\033\056\046\118\124\234\064" ; 20, 59, 7, 119, 797, "20:59:07.119797", "\083\066\176\234\177\113\242\064" ; 20, 15, 7, 180, 878, "20:15:07.180878", "\105\084\224\228\178\204\241\064" ; 1, 56, 15, 978, 868, "01:56:15.978868", "\026\223\023\151\250\063\187\064" ; 9, 52, 40, 202, 405, "09:52:40.202405", "\241\012\026\122\006\093\225\064" ; 4, 20, 9, 482, 351, "04:20:09.482351", "\025\117\173\189\189\124\206\064" ; 3, 43, 11, 629, 371, "03:43:11.629371", "\007\155\058\143\208\039\202\064" ; 4, 22, 9, 599, 919, "04:22:09.599919", "\160\082\037\202\204\184\206\064" ; 2, 11, 1, 198, 838, "02:11:01.198838", "\052\019\012\231\050\181\190\064" ; 12, 53, 37, 862, 327, "12:53:37.862327", "\239\202\046\152\059\170\230\064" ; 10, 43, 43, 857, 342, "10:43:43.857342", "\112\125\088\111\251\219\226\064" ; 16, 50, 17, 826, 266, "16:50:17.826266", "\250\100\197\112\058\153\237\064" ; 2, 50, 52, 42, 731, "02:50:52.042731", "\195\155\053\120\005\006\196\064" ; 21, 8, 59, 763, 948, "21:08:59.763948", "\190\137\033\057\188\150\242\064" ; 4, 11, 20, 371, 543, "04:11:20.371543", "\007\149\184\142\047\116\205\064" ; 19, 39, 31, 769, 606, "19:39:31.769606", "\141\097\078\080\060\071\241\064" ; 0, 44, 54, 968, 154, "00:44:54.968154", "\251\142\225\177\239\013\165\064" ; 1, 12, 47, 26, 950, "01:12:47.026950", "\160\248\049\230\006\015\177\064" ; 13, 57, 10, 270, 375, "13:57:10.270375", "\213\120\233\166\200\134\232\064" ; 18, 0, 0, 934, 202, "18:00:00.934202", "\188\151\251\228\029\164\239\064" ; 5, 40, 59, 118, 942, "05:40:59.118942", "\007\232\190\156\199\250\211\064" ; 6, 45, 36, 814, 61, "06:45:36.814061", "\252\078\147\025\052\196\215\064" ; 1, 1, 3, 776, 27, "01:01:03.776027", "\160\051\105\083\141\159\172\064" ; 12, 29, 2, 60, 948, "12:29:02.060948", "\088\056\073\243\193\241\229\064" ; 12, 24, 45, 838, 713, "12:24:45.838713", "\056\165\188\214\186\209\229\064" ; 6, 25, 23, 741, 676, "06:25:23.741676", "\015\157\158\119\239\148\214\064" ; 10, 15, 38, 173, 985, "10:15:38.173985", "\160\253\072\145\069\009\226\064" ; 9, 20, 5, 588, 446, "09:20:05.588446", "\175\180\140\212\178\104\224\064" ; 19, 12, 27, 669, 11, "19:12:27.669011", "\218\224\068\180\186\225\240\064" ; 15, 13, 10, 254, 291, "15:13:10.254291", "\021\225\038\035\200\192\234\064" ; 10, 0, 45, 767, 920, "10:00:45.767920", "\190\246\204\146\184\153\225\064" ; 2, 3, 29, 676, 327, "02:03:29.676327", "\103\042\196\035\173\241\188\064" ; 12, 29, 12, 626, 294, "12:29:12.626294", "\245\182\153\010\020\243\229\064" ; 1, 54, 27, 145, 3, "01:54:27.145003", "\211\166\234\030\037\211\186\064" ; 8, 21, 41, 437, 688, "08:21:41.437688", "\119\135\020\003\092\101\221\064" ; 7, 6, 55, 892, 309, "07:06:55.892309", "\059\053\151\027\249\003\217\064" ; 13, 20, 52, 505, 635, "13:20:52.505635", "\150\115\041\046\144\118\231\064" ; 9, 35, 15, 513, 875, "09:35:15.513875", "\231\251\169\113\112\218\224\064" ; 20, 12, 1, 437, 191, "20:12:01.437191", "\114\253\187\254\022\193\241\064" ; 3, 47, 54, 457, 815, "03:47:54.457815", "\079\146\174\153\058\181\202\064" ; 1, 28, 35, 435, 553, "01:28:35.435553", "\173\194\102\128\111\195\180\064" ; 23, 26, 46, 494, 747, "23:26:46.494747", "\141\212\123\234\103\155\244\064" ; 23, 35, 22, 670, 543, "23:35:22.670543", "\249\075\139\186\170\187\244\064" ; 17, 25, 0, 37, 533, "17:25:00.037533", "\240\103\120\051\129\157\238\064" ; 8, 56, 25, 790, 223, "08:56:25.790223", "\099\125\003\147\114\110\223\064" ; 0, 43, 55, 700, 941, "00:43:55.700941", "\217\030\189\225\102\151\164\064" ; 21, 9, 12, 582, 973, "21:09:12.582973", "\023\127\219\083\137\151\242\064" ; 5, 51, 36, 27, 548, "05:51:36.027548", "\196\175\088\195\001\154\212\064" ; 8, 54, 29, 632, 754, "08:54:29.632754", "\027\162\010\127\104\081\223\064" ; 1, 39, 7, 321, 995, "01:39:07.321995", "\122\170\067\110\082\059\183\064" ; 12, 53, 13, 241, 334, "12:53:13.241334", "\173\020\002\185\039\167\230\064" ; 3, 0, 33, 786, 112, "03:00:33.786112", "\127\105\081\159\228\040\197\064" ; 0, 34, 39, 492, 225, "00:34:39.492225", "\140\074\234\004\252\062\160\064" ; 22, 19, 58, 691, 267, "22:19:58.691267", "\093\252\109\015\235\160\243\064" ; 4, 24, 49, 730, 785, "04:24:49.730785", "\180\229\092\138\221\008\207\064" ; 8, 2, 2, 562, 738, "08:02:02.562738", "\142\062\230\003\164\062\220\064" ; 1, 20, 39, 287, 536, "01:20:39.287536", "\108\148\245\155\073\231\178\064" ; 15, 2, 58, 586, 130, "15:02:58.586130", "\167\179\147\193\082\116\234\064" ; 4, 8, 46, 809, 572, "04:08:46.809572", "\225\039\014\160\103\039\205\064" ; 13, 29, 2, 838, 595, "13:29:02.838595", "\115\046\197\213\218\179\231\064" ; 10, 26, 1, 130, 500, "10:26:01.130500", "\004\086\014\045\036\087\226\064" ; 20, 56, 12, 945, 391, "20:56:12.945391", "\047\080\082\032\207\102\242\064" ; 3, 28, 1, 222, 501, "03:28:01.222501", "\042\171\233\122\156\096\200\064" ; 4, 42, 10, 970, 407, "04:42:10.970407", "\052\246\037\027\190\136\208\064" ; 4, 39, 35, 666, 387, "04:39:35.666387", "\223\168\021\166\234\097\208\064" ; 9, 10, 39, 639, 586, "09:10:39.639586", "\032\015\125\119\244\033\224\064" ; 14, 8, 55, 5, 740, "14:08:55.005740", "\009\167\005\047\224\222\232\064" ; 7, 57, 2, 134, 696, "07:57:02.134696", "\185\248\219\158\136\243\219\064" ; 3, 10, 32, 108, 207, "03:10:32.108207", "\025\027\186\217\013\084\198\064" ; 17, 38, 49, 761, 31, "17:38:49.761031", "\008\175\093\090\056\005\239\064" ; 22, 51, 46, 324, 764, "22:51:46.324764", "\110\188\059\050\037\024\244\064" ; 4, 40, 38, 340, 44, "04:40:38.340044", "\205\232\071\195\149\113\208\064" ; 22, 17, 32, 532, 347, "22:17:32.532347", "\178\073\126\132\200\151\243\064" ; 11, 37, 8, 274, 852, "11:37:08.274852", "\231\107\150\203\136\108\228\064" ; 22, 13, 42, 247, 413, "22:13:42.247413", "\122\085\103\245\099\137\243\064" ; 10, 22, 10, 417, 622, "10:22:10.417622", "\003\208\040\093\077\058\226\064" ; 13, 21, 17, 606, 279, "13:21:17.606279", "\168\055\163\102\179\121\231\064" ; 6, 55, 56, 962, 679, "06:55:56.962679", "\099\097\136\156\061\095\216\064" ; 1, 4, 49, 686, 838, "01:04:49.686838", "\077\247\058\169\095\099\174\064" ; 0, 14, 15, 345, 910, "00:14:15.345910", "\224\074\118\108\196\186\138\064" ; 20, 13, 19, 851, 99, "20:13:19.851099", "\042\252\025\158\253\197\241\064" ; 4, 49, 15, 844, 460, "04:49:15.844460", "\178\244\161\011\246\242\208\064" ; 16, 3, 27, 22, 631, "16:03:27.022631", "\156\165\100\185\224\057\236\064" ; 22, 45, 47, 176, 36, "22:45:47.176036", "\239\031\011\209\178\001\244\064" ; 3, 11, 39, 976, 953, "03:11:39.976953", "\094\192\203\012\253\117\198\064" ; 11, 20, 12, 649, 469, "11:20:12.649469", "\088\054\115\200\148\237\227\064" ; 22, 45, 40, 420, 146, "22:45:40.420146", "\025\003\235\184\070\001\244\064" ; 17, 2, 20, 598, 992, "17:02:20.598992", "\082\069\241\042\147\243\237\064" ; 13, 42, 14, 323, 208, "13:42:14.323208", "\185\077\184\087\202\022\232\064" ; 21, 51, 49, 441, 775, "21:51:49.441775", "\147\169\130\017\087\055\243\064" ; 22, 6, 33, 82, 67, "22:06:33.082067", "\145\124\037\080\145\110\243\064" ; 1, 59, 57, 592, 378, "01:59:57.592378", "\222\168\021\166\151\029\188\064" ; 4, 45, 50, 656, 775, "04:45:50.656775", "\117\002\154\008\170\191\208\064" ; 19, 44, 42, 839, 152, "19:44:42.839152", "\198\165\042\109\173\090\241\064" ; 5, 24, 37, 818, 616, "05:24:37.818616", "\255\092\052\100\116\005\211\064" ; 16, 58, 9, 264, 988, "16:58:09.264988", "\059\029\200\122\040\212\237\064" ; 19, 22, 31, 445, 835, "19:22:31.445835", "\135\225\035\034\119\007\241\064" ; 3, 54, 58, 537, 711, "03:54:58.537711", "\218\203\182\211\068\137\203\064" ; 0, 41, 17, 476, 265, "00:41:17.476265", "\118\142\001\217\243\090\163\064" ; 20, 17, 1, 68, 243, "20:17:01.068243", "\211\248\133\023\209\211\241\064" ; 11, 30, 6, 193, 315, "11:30:06.193315", "\090\240\162\047\198\055\228\064" ; 16, 58, 29, 159, 337, "16:58:29.159337", "\129\232\073\025\165\214\237\064" ; 16, 15, 51, 625, 470, "16:15:51.625470", "\084\169\217\003\244\150\236\064" ; 2, 38, 44, 697, 158, "02:38:44.697158", "\019\045\121\060\089\154\194\064" ; 2, 11, 30, 168, 675, "02:11:30.168675", "\167\232\072\046\043\210\190\064" ; 2, 43, 33, 457, 852, "02:43:33.457852", "\052\243\228\154\186\042\195\064" ; 14, 33, 35, 91, 943, "14:33:35.091943", "\067\114\050\241\226\151\233\064" ; 6, 57, 56, 331, 670, "06:57:56.331670", "\196\206\020\058\021\125\216\064" ; 18, 20, 28, 162, 432, "18:20:28.162432", "\253\075\082\153\194\030\240\064" ; 2, 55, 1, 93, 652, "02:55:01.093652", "\155\234\201\252\139\130\196\064" ; 16, 14, 53, 808, 82, "16:14:53.808082", "\079\200\206\219\185\143\236\064" ; 21, 27, 36, 806, 129, "21:27:36.806129", "\181\133\231\229\140\220\242\064" ; 8, 38, 39, 421, 0, "08:38:39.421000", "\231\251\169\241\218\099\222\064" ; 10, 21, 21, 381, 670, "10:21:21.381670", "\252\000\164\054\044\052\226\064" ; 17, 37, 52, 59, 146, "17:37:52.059146", "\246\038\134\228\001\254\238\064" ; 22, 41, 11, 337, 900, "22:41:11.337900", "\149\212\009\104\117\240\243\064" ; 22, 38, 39, 224, 29, "22:38:39.224029", "\198\110\159\149\243\230\243\064" ; 20, 2, 47, 625, 830, "20:02:47.625830", "\110\081\102\003\122\158\241\064" ; 21, 45, 16, 851, 779, "21:45:16.851779", "\070\004\227\160\205\030\243\064" ; 11, 22, 21, 895, 881, "11:22:21.895881", "\131\161\014\171\188\253\227\064" ; 5, 17, 39, 425, 369, "05:17:39.425369", "\239\229\062\057\219\156\210\064" ; 18, 59, 11, 946, 887, "18:59:11.946887", "\160\251\114\038\255\175\240\064" ; 6, 41, 23, 208, 946, "06:41:23.208946", "\040\011\095\095\205\132\215\064" ; 13, 56, 8, 35, 197, "13:56:08.035197", "\126\117\085\032\001\127\232\064" ; 3, 11, 21, 409, 701, "03:11:21.409701", "\018\022\021\113\180\108\198\064" ; 8, 59, 51, 1, 751, "08:59:51.001751", "\239\057\176\028\192\161\223\064" ; 18, 24, 14, 733, 59, "18:24:14.733059", "\240\018\156\186\235\044\240\064" ; 17, 8, 51, 732, 536, "17:08:51.732536", "\101\086\239\112\119\036\238\064" ; 15, 36, 41, 568, 839, "15:36:41.568839", "\182\216\237\051\050\113\235\064" ; 3, 28, 28, 802, 603, "03:28:28.802603", "\086\242\177\187\102\110\200\064" ; 18, 50, 49, 519, 954, "18:50:49.519954", "\023\073\187\081\152\144\240\064" ; 16, 31, 23, 156, 525, "16:31:23.156525", "\129\183\064\002\101\011\237\064" ; 7, 5, 26, 899, 139, "07:05:26.899139", "\228\077\126\139\185\237\216\064" ; 7, 1, 52, 711, 86, "07:01:52.711086", "\169\218\110\130\045\184\216\064" ; 7, 30, 46, 781, 947, "07:30:46.781947", "\013\110\107\011\178\105\218\064" ; 9, 12, 2, 158, 349, "09:12:02.158349", "\012\236\049\017\069\044\224\064" ; 5, 27, 33, 448, 559, "05:27:33.448559", "\213\206\048\181\092\049\211\064" ; 10, 19, 3, 394, 826, "10:19:03.394826", "\180\034\106\162\236\034\226\064" ; 0, 31, 16, 928, 659, "00:31:16.928659", "\140\136\098\242\182\083\157\064" ; 9, 7, 55, 66, 381, "09:07:55.066381", "\002\012\203\031\098\013\224\064" ; 5, 51, 8, 498, 359, "05:51:08.498359", "\171\037\029\229\031\147\212\064" ; 2, 37, 41, 655, 965, "02:37:41.655965", "\041\063\169\246\211\122\194\064" ; 13, 31, 59, 205, 818, "13:31:59.205818", "\094\161\015\150\230\201\231\064" ; 19, 17, 10, 757, 245, "19:17:10.757245", "\225\238\172\029\108\243\240\064" ; 1, 21, 24, 967, 430, "01:21:24.967430", "\043\019\126\169\247\020\179\064" ; 9, 44, 44, 544, 503, "09:44:44.544503", "\051\142\145\108\145\033\225\064" ; 9, 12, 15, 37, 753, "09:12:15.037753", "\138\199\069\053\225\045\224\064" ; 9, 51, 47, 955, 918, "09:51:47.955918", "\117\088\225\150\126\086\225\064" ; 1, 43, 35, 236, 797, "01:43:35.236797", "\202\106\186\158\060\071\184\064" ; 15, 26, 3, 713, 538, "15:26:03.713538", "\207\164\077\213\118\033\235\064" ; 7, 25, 36, 571, 532, "07:25:36.571532", "\039\244\250\147\036\028\218\064" ; 12, 46, 0, 968, 930, "12:46:00.968930", "\196\124\121\001\031\113\230\064" ; 15, 51, 21, 717, 768, "15:51:21.717768", "\195\152\244\247\054\223\235\064" ; 9, 1, 24, 857, 847, "09:01:24.857847", "\126\026\247\230\054\185\223\064" ; 20, 15, 35, 651, 306, "20:15:35.651306", "\027\215\191\107\122\206\241\064" ; 9, 59, 33, 976, 894, "09:59:33.976894", "\181\052\183\066\191\144\225\064" ; 11, 8, 51, 56, 499, "11:08:51.056499", "\168\253\214\206\097\152\227\064" ; 3, 2, 42, 798, 955, "03:02:42.798955", "\253\077\040\068\102\105\197\064" ; 4, 15, 10, 582, 839, "04:15:10.582839", "\235\229\119\154\074\231\205\064" ; 16, 49, 52, 835, 745, "16:49:52.835745", "\089\076\108\190\026\150\237\064" ; 17, 37, 39, 951, 929, "17:37:39.951929", "\100\206\051\118\126\252\238\064" ; 19, 56, 3, 489, 21, "19:56:03.489021", "\033\175\007\211\055\133\241\064" ; 14, 3, 7, 338, 571, "14:03:07.338571", "\140\217\146\213\106\179\232\064" ; 21, 38, 27, 302, 444, "21:38:27.302444", "\014\133\207\214\052\005\243\064" ; 6, 26, 33, 716, 692, "06:26:33.716692", "\084\031\072\222\109\166\214\064" ; 6, 10, 52, 612, 65, "06:10:52.612065", "\130\173\018\044\039\187\213\064" ; 20, 53, 16, 135, 829, "20:53:16.135829", "\141\007\091\044\194\091\242\064" ; 20, 33, 47, 250, 133, "20:33:47.250133", "\234\117\139\000\180\018\242\064" ; 4, 32, 51, 405, 69, "04:32:51.405069", "\208\013\077\217\179\249\207\064" ; 17, 0, 42, 475, 570, "17:00:42.475570", "\158\147\222\055\079\231\237\064" ; 6, 32, 47, 338, 0, "06:32:47.338000", "\131\192\202\161\213\003\215\064" ; 13, 52, 47, 431, 869, "13:52:47.431869", "\229\239\222\209\237\101\232\064" ; 13, 32, 58, 70, 185, "13:32:58.070185", "\245\156\244\062\066\209\231\064" ; 2, 38, 26, 904, 941, "02:38:26.904941", "\232\079\027\213\115\145\194\064" ; 0, 31, 25, 170, 598, "00:31:25.170598", "\014\251\061\177\174\116\157\064" ; 0, 20, 38, 202, 908, "00:20:38.202908", "\099\096\029\199\207\088\147\064" ; 8, 36, 16, 157, 643, "08:36:16.157643", "\092\170\210\022\010\064\222\064" ; 6, 49, 40, 460, 226, "06:49:40.460226", "\177\192\087\116\029\001\216\064" ; 3, 52, 48, 360, 133, "03:52:48.360133", "\155\144\214\024\046\072\203\064" ; 6, 38, 3, 233, 249, "06:38:03.233249", "\181\054\141\237\206\082\215\064" ; 9, 52, 24, 586, 231, "09:52:24.586231", "\157\131\103\194\018\091\225\064" ; 12, 53, 33, 383, 730, "12:53:33.383730", "\016\035\132\071\172\169\230\064" ; 20, 39, 37, 234, 39, "20:39:37.234039", "\176\173\159\190\147\040\242\064" ; 8, 3, 32, 376, 785, "08:03:32.376785", "\040\213\062\029\024\085\220\064" ; 18, 23, 26, 166, 562, "18:23:26.166562", "\108\234\060\170\226\041\240\064" ; 23, 23, 37, 225, 478, "23:23:37.225478", "\192\209\142\155\147\143\244\064" ; 19, 11, 28, 725, 486, "19:11:28.725486", "\060\053\151\155\011\222\240\064" ; 19, 54, 27, 605, 446, "19:54:27.605446", "\024\037\232\175\057\127\241\064" ; 2, 19, 11, 27, 238, "02:19:11.027238", "\155\231\136\124\131\079\192\064" ; 2, 43, 53, 302, 984, "02:43:53.302984", "\155\001\046\200\166\052\195\064" ; 20, 45, 38, 811, 991, "20:45:38.811991", "\090\070\234\253\044\063\242\064" ; 7, 41, 14, 458, 378, "07:41:14.458378", "\205\173\016\086\157\006\219\064" ; 20, 47, 5, 18, 831, "20:47:05.018831", "\018\188\033\077\144\068\242\064" ; 12, 50, 41, 400, 81, "12:50:41.400081", "\088\171\118\205\044\148\230\064" ; 5, 22, 16, 475, 226, "05:22:16.475226", "\013\080\026\106\030\226\210\064" ; 8, 20, 48, 548, 235, "08:20:48.548235", "\225\064\072\022\035\088\221\064" ; 0, 29, 56, 742, 316, "00:29:56.742316", "\049\125\175\033\248\018\156\064" ; 12, 1, 12, 239, 931, "12:01:12.239931", "\202\198\131\173\007\033\229\064" ; 14, 29, 57, 450, 569, "14:29:57.450569", "\243\173\015\107\174\124\233\064" ; 1, 46, 26, 258, 145, "01:46:26.258145", "\160\108\202\021\066\242\184\064" ; 3, 36, 54, 828, 508, "03:36:54.828508", "\060\214\140\012\106\107\201\064" ; 13, 39, 38, 704, 631, "13:39:38.704631", "\152\079\086\140\086\003\232\064" ; 4, 17, 43, 995, 259, "04:17:43.995259", "\007\156\165\100\255\051\206\064" ; 6, 19, 43, 539, 48, "06:19:43.539048", "\191\046\195\127\226\063\214\064" ; 21, 6, 15, 821, 382, "21:06:15.821382", "\184\115\097\036\125\140\242\064" ; 22, 16, 46, 560, 910, "22:16:46.560910", "\160\195\124\249\232\148\243\064" ; 6, 19, 34, 947, 532, "06:19:34.947532", "\250\065\093\164\188\061\214\064" ; 3, 24, 47, 189, 482, "03:24:47.189482", "\151\056\242\064\152\255\199\064" ; 13, 25, 59, 148, 624, "13:25:59.148624", "\109\030\135\193\228\156\231\064" ; 13, 20, 58, 118, 47, "13:20:58.118047", "\141\128\010\199\067\119\231\064" ; 9, 48, 3, 837, 296, "09:48:03.837296", "\034\251\032\203\122\058\225\064" ; 19, 12, 47, 190, 896, "19:12:47.190896", "\207\246\232\013\243\226\240\064" ; 7, 54, 54, 82, 716, "07:54:54.082716", "\182\012\056\075\133\211\219\064" ; 18, 37, 20, 880, 231, "18:37:20.880231", "\223\025\109\021\014\094\240\064" ; 5, 35, 36, 828, 565, "05:35:36.828565", "\103\126\053\007\053\170\211\064" ; 18, 22, 45, 150, 267, "18:22:45.150267", "\170\094\126\103\082\039\240\064" ; 20, 0, 16, 541, 691, "20:00:16.541691", "\152\046\196\170\008\149\241\064" ; 16, 10, 35, 475, 604, "16:10:35.475604", "\059\225\037\056\111\111\236\064" ; 21, 58, 47, 328, 102, "21:58:47.328102", "\252\225\231\063\117\081\243\064" ; 17, 28, 12, 984, 178, "17:28:12.984178", "\110\220\098\126\159\181\238\064" ; 14, 37, 26, 158, 18, "14:37:26.158018", "\198\195\123\014\197\180\233\064" ; 6, 9, 41, 571, 831, "06:09:41.571831", "\246\012\225\152\100\169\213\064" ; 18, 18, 14, 468, 617, "18:18:14.468617", "\021\138\116\127\103\022\240\064" ; 9, 23, 48, 128, 642, "09:23:48.128642", "\220\211\213\029\132\132\224\064" ; 9, 5, 0, 583, 278, "09:05:00.583278", "\158\063\109\084\037\239\223\064" ; 0, 18, 27, 855, 956, "00:18:27.855956", "\067\203\186\127\108\079\145\064" ; 10, 14, 29, 938, 724, "10:14:29.938724", "\255\233\006\010\190\000\226\064" ; 17, 10, 14, 6, 237, "17:10:14.006237", "\225\239\023\051\192\046\238\064" ; 9, 55, 10, 365, 299, "09:55:10.365299", "\072\135\135\176\203\111\225\064" ; 23, 53, 31, 256, 75, "23:53:31.256075", "\101\025\226\024\180\255\244\064" ; 18, 19, 29, 356, 909, "18:19:29.356909", "\042\054\230\181\021\027\240\064" ; 17, 51, 49, 134, 9, "17:51:49.134009", "\012\062\205\073\164\102\239\064" ; 2, 7, 49, 942, 730, "02:07:49.942730", "\245\214\192\086\241\245\189\064" ; 13, 4, 40, 250, 61, "13:04:40.250061", "\032\237\127\000\008\253\230\064" ; 20, 10, 7, 595, 875, "20:10:07.595875", "\088\057\180\136\249\185\241\064" ; 6, 44, 16, 421, 837, "06:44:16.421837", "\207\157\096\255\026\176\215\064" ; 3, 20, 49, 733, 798, "03:20:49.733798", "\239\197\023\237\221\136\199\064" ; 7, 52, 37, 873, 469, "07:52:37.873469", "\068\133\234\230\119\177\219\064" ; 12, 34, 44, 67, 778, "12:34:44.067778", "\173\196\060\043\130\028\230\064" ; 14, 13, 49, 230, 353, "14:13:49.230353", "\050\065\013\095\167\003\233\064" ; 17, 44, 49, 108, 500, "17:44:49.108500", "\244\253\212\120\035\050\239\064" ; 10, 51, 28, 939, 555, "10:51:28.939555", "\185\165\213\016\030\022\227\064" ; 2, 41, 47, 675, 476, "02:41:47.675476", "\157\096\255\117\214\245\194\064" ; 9, 7, 26, 757, 308, "09:07:26.757308", "\160\252\221\059\216\009\224\064" ; 20, 18, 26, 846, 386, "20:18:26.846386", "\221\011\204\138\045\217\241\064" ; 15, 17, 29, 852, 334, "15:17:29.852334", "\232\243\081\070\059\225\234\064" ; 16, 40, 19, 720, 768, "16:40:19.720768", "\128\013\136\016\119\078\237\064" ; 11, 6, 21, 802, 171, "11:06:21.802171", "\090\132\098\171\185\133\227\064" ; 16, 7, 43, 667, 460, "16:07:43.667460", "\237\018\213\091\245\089\236\064" ; 5, 15, 21, 55, 9, "05:15:21.055009", "\255\119\068\133\067\122\210\064" ; 1, 30, 32, 798, 272, "01:30:32.798272", "\080\197\141\091\204\056\181\064" ; 7, 44, 33, 201, 538, "07:44:33.201538", "\186\163\255\229\076\056\219\064" ; 3, 8, 12, 126, 836, "03:08:12.126836", "\250\123\041\060\016\014\198\064" ; 17, 6, 3, 17, 407, "17:06:03.017407", "\247\031\153\142\096\015\238\064" ; 15, 41, 45, 540, 988, "15:41:45.540988", "\241\016\198\079\049\151\235\064" ; 5, 44, 32, 596, 121, "05:44:32.596121", "\222\177\216\038\038\048\212\064" ; 5, 54, 10, 438, 689, "05:54:10.438689", "\007\007\123\019\156\192\212\064" ; 14, 52, 33, 760, 381, "14:52:33.760381", "\240\136\010\085\056\038\234\064" ; 21, 32, 34, 526, 594, "21:32:34.526594", "\132\212\237\108\040\239\242\064" ; 11, 45, 59, 525, 900, "11:45:59.525900", "\159\060\044\212\240\174\228\064" ; 20, 35, 59, 903, 501, "20:35:59.903501", "\239\118\189\116\254\026\242\064" ; 21, 16, 18, 463, 69, "21:16:18.463069", "\045\010\187\104\039\178\242\064" ; 13, 43, 47, 338, 367, "13:43:47.338367", "\226\007\231\211\106\034\232\064" ; 20, 39, 26, 722, 590, "20:39:26.722590", "\038\136\186\143\235\039\242\064" ; 1, 30, 26, 694, 320, "01:30:26.694320", "\246\156\244\190\177\050\181\064" ; 10, 32, 50, 453, 343, "10:32:50.453343", "\220\045\201\129\078\138\226\064" ; 19, 21, 37, 545, 326, "19:21:37.545326", "\122\193\167\185\024\004\241\064" ; 12, 15, 49, 142, 850, "12:15:49.142850", "\199\041\058\146\164\142\229\064" ; 23, 6, 17, 946, 858, "23:06:17.946858", "\255\146\084\038\159\078\244\064" ; 19, 11, 2, 531, 663, "19:11:02.531663", "\216\015\177\129\104\220\240\064" ; 9, 25, 46, 791, 434, "09:25:46.791434", "\094\101\109\083\089\147\224\064" ; 1, 41, 56, 787, 88, "01:41:56.787088", "\019\099\153\126\201\228\183\064" ; 1, 49, 0, 410, 85, "01:49:00.410085", "\148\159\084\251\104\140\185\064" ; 12, 27, 13, 635, 140, "12:27:13.635140", "\012\031\017\083\052\228\229\064" ; 13, 15, 3, 976, 99, "13:15:03.976099", "\085\248\051\060\255\074\231\064" ; 6, 47, 26, 953, 850, "06:47:26.953850", "\211\222\224\011\189\223\215\064" ; 15, 54, 35, 894, 81, "15:54:35.894081", "\223\193\079\156\124\247\235\064" ; 23, 50, 8, 462, 586, "23:50:08.462586", "\217\147\192\102\007\243\244\064" ; 20, 13, 20, 197, 448, "20:13:20.197448", "\235\059\191\040\003\198\241\064" ; 8, 16, 17, 462, 145, "08:16:17.462145", "\065\159\200\147\093\020\221\064" ; 8, 25, 56, 104, 538, "08:25:56.104538", "\204\038\192\176\006\165\221\064" ; 22, 21, 43, 917, 479, "22:21:43.917479", "\188\117\254\173\126\167\243\064" ; 17, 47, 34, 920, 436, "17:47:34.920436", "\194\050\054\116\221\070\239\064" ; 12, 59, 22, 552, 36, "12:59:22.552036", "\199\102\071\170\081\213\230\064" ; 6, 14, 49, 822, 274, "06:14:49.822274", "\151\032\035\160\116\246\213\064" ; 11, 59, 37, 910, 286, "11:59:37.910286", "\001\027\016\033\061\021\229\064" ; 11, 10, 40, 830, 447, "11:10:40.830447", "\066\150\005\147\026\166\227\064" ; 23, 33, 40, 472, 198, "23:33:40.472198", "\115\125\031\142\071\181\244\064" ; 4, 49, 24, 11, 632, "04:49:24.011632", "\229\036\148\190\000\245\208\064" ; 1, 10, 24, 490, 145, "01:10:24.490145", "\076\137\036\122\125\128\176\064" ; 14, 14, 42, 187, 872, "14:14:42.187872", "\250\035\012\003\070\010\233\064" ; 3, 44, 32, 76, 108, "03:44:32.076108", "\123\045\232\189\009\080\202\064" ; 14, 18, 2, 770, 866, "14:18:02.770866", "\115\044\239\170\088\035\233\064" ; 5, 54, 22, 417, 336, "05:54:22.417336", "\221\013\162\181\154\195\212\064" ; 6, 35, 59, 353, 868, "06:35:59.353868", "\198\247\197\165\214\051\215\064" ; 16, 32, 58, 518, 60, "16:32:58.518060", "\171\144\242\147\080\023\237\064" ; 17, 16, 28, 176, 534, "17:16:28.176534", "\148\161\042\166\133\093\238\064" ; 15, 38, 8, 819, 716, "15:38:08.819716", "\129\012\029\059\026\124\235\064" ; 19, 45, 31, 454, 997, "19:45:31.454997", "\044\239\170\071\183\093\241\064" ; 11, 19, 16, 8, 266, "11:19:16.008266", "\246\014\183\067\128\230\227\064" ; 9, 44, 16, 176, 96, "09:44:16.176096", "\031\020\148\162\005\030\225\064" ; 11, 8, 10, 277, 326, "11:08:10.277326", "\139\198\218\223\072\147\227\064" ; 9, 33, 1, 49, 525, "09:33:01.049525", "\235\115\181\149\161\201\224\064" ; 7, 31, 29, 236, 150, "07:31:29.236150", "\189\227\020\029\079\116\218\064" ; 2, 31, 48, 382, 593, "02:31:48.382593", "\087\179\206\248\048\202\193\064" ; 0, 43, 8, 945, 658, "00:43:08.945658", "\103\014\073\045\228\057\164\064" ; 7, 56, 17, 346, 619, "07:56:17.346619", "\075\117\001\047\086\232\219\064" ; 16, 57, 25, 320, 391, "16:57:25.320391", "\094\160\164\064\170\206\237\064" ; 10, 44, 16, 356, 96, "10:44:16.356096", "\072\112\035\101\011\224\226\064" ; 0, 34, 29, 550, 980, "00:34:29.550980", "\128\241\012\026\026\043\160\064" ; 18, 6, 50, 557, 668, "18:06:50.557668", "\193\143\106\216\081\215\239\064" ; 6, 7, 6, 709, 89, "06:07:06.709089", "\061\212\182\097\173\130\213\064" ; 22, 38, 20, 71, 46, "22:38:20.071046", "\104\033\001\035\193\229\243\064" ; 19, 18, 16, 738, 879, "19:18:16.738879", "\075\201\114\210\139\247\240\064" ; 10, 25, 50, 931, 247, "10:25:50.931247", "\048\130\198\204\221\085\226\064" ; 4, 1, 23, 840, 53, "04:01:23.840053", "\244\080\219\134\235\073\204\064" ; 17, 32, 38, 94, 338, "17:32:38.094338", "\024\032\209\004\195\214\238\064" ; 20, 41, 25, 436, 998, "20:41:25.436998", "\103\157\241\253\086\047\242\064" ; 3, 3, 52, 550, 444, "03:03:52.550444", "\035\241\242\116\070\140\197\064" ; 16, 1, 40, 344, 322, "16:01:40.344322", "\041\146\175\004\139\044\236\064" ; 13, 45, 56, 910, 824, "13:45:56.910824", "\142\095\120\037\157\050\232\064" ; 15, 39, 11, 671, 597, "15:39:11.671597", "\227\253\184\125\245\131\235\064" ; 9, 23, 52, 858, 679, "09:23:52.858679", "\216\097\076\122\027\133\224\064" ; 20, 50, 34, 458, 626, "20:50:34.458626", "\113\055\136\086\167\081\242\064" ; 20, 36, 2, 999, 999, "20:36:02.999999", "\144\243\254\255\047\027\242\064" ; 6, 29, 51, 550, 173, "06:29:51.550173", "\137\208\008\054\227\215\214\064" ; 0, 36, 46, 414, 516, "00:36:46.414516", "\087\239\112\059\212\060\161\064" ; 23, 51, 10, 16, 758, "23:51:10.016758", "\095\009\164\068\224\246\244\064" ; 20, 42, 34, 303, 800, "20:42:34.303800", "\136\099\093\220\164\051\242\064" ; 3, 39, 29, 799, 816, "03:39:29.799816", "\105\229\094\096\230\184\201\064" ; 11, 21, 58, 240, 831, "11:21:58.240831", "\155\054\227\180\199\250\227\064" ; 20, 21, 15, 676, 205, "20:21:15.676205", "\135\085\188\209\186\227\241\064" ; 18, 39, 48, 825, 732, "18:39:48.825732", "\244\193\050\054\077\103\240\064" ; 10, 4, 59, 682, 781, "10:04:59.682781", "\043\138\087\217\117\185\225\064" ; 3, 7, 30, 9, 195, "03:07:30.009195", "\037\064\077\045\001\249\197\064" ; 2, 40, 18, 312, 371, "02:40:18.312371", "\156\222\197\251\039\201\194\064" ; 16, 17, 50, 209, 964, "16:17:50.209964", "\043\108\006\184\198\165\236\064" ; 12, 33, 13, 769, 649, "12:33:13.769649", "\141\240\246\160\056\017\230\064" ; 12, 15, 58, 321, 131, "12:15:58.321131", "\216\132\180\070\202\143\229\064" ; 22, 37, 55, 575, 879, "22:37:55.575879", "\247\229\204\054\057\228\243\064" ; 20, 39, 24, 343, 824, "20:39:24.343824", "\057\152\077\128\197\039\242\064" ; 12, 44, 41, 691, 127, "12:44:41.691127", "\204\094\182\029\054\103\230\064" ; 9, 16, 58, 649, 897, "09:16:58.649897", "\024\203\244\203\084\081\224\064" ; 5, 13, 18, 682, 420, "05:13:18.682420", "\137\239\196\172\171\091\210\064" ; 20, 23, 14, 43, 338, "20:23:14.043338", "\203\047\131\177\032\235\241\064" ; 21, 57, 19, 806, 913, "21:57:19.806913", "\027\155\029\233\252\075\243\064" ; 19, 26, 49, 526, 232, "19:26:49.526232", "\226\062\114\107\152\023\241\064" ; 8, 29, 54, 553, 334, "08:29:54.553334", "\113\002\211\105\163\224\221\064" ; 11, 20, 39, 910, 198, "11:20:39.910198", "\093\142\087\032\253\240\227\064" ; 3, 37, 3, 686, 559, "03:37:03.686559", "\227\081\042\225\215\111\201\064" ; 2, 42, 46, 128, 442, "02:42:46.128442", "\184\150\201\112\016\019\195\064" ; 17, 44, 27, 175, 969, "17:44:27.175969", "\132\189\137\161\101\047\239\064" ; 4, 52, 21, 753, 434, "04:52:21.753434", "\109\061\067\056\112\033\209\064" ; 8, 34, 20, 923, 160, "08:34:20.923160", "\062\174\013\021\059\035\222\064" ; 0, 48, 54, 223, 494, "00:48:54.223494", "\180\057\206\109\114\236\166\064" ; 15, 59, 30, 107, 585, "15:59:30.107585", "\018\025\086\113\067\028\236\064" ; 16, 28, 8, 688, 644, "16:28:08.688644", "\083\036\095\009\022\243\236\064" ; 22, 22, 45, 236, 503, "22:22:45.236503", "\167\094\183\200\083\171\243\064" ; 16, 24, 44, 894, 595, "16:24:44.894595", "\133\177\133\160\156\217\236\064" ; 2, 58, 12, 493, 124, "02:58:12.493124", "\112\238\175\030\063\226\196\064" ; 4, 38, 31, 346, 101, "04:38:31.346101", "\008\207\132\038\214\081\208\064" ; 23, 48, 1, 386, 911, "23:48:01.386911", "\183\150\201\048\022\235\244\064" ; 15, 54, 15, 751, 931, "15:54:15.751931", "\187\153\209\015\248\244\235\064" ; 10, 38, 6, 793, 195, "10:38:06.793195", "\011\123\218\097\217\177\226\064" ; 16, 28, 39, 414, 172, "16:28:39.414172", "\093\163\229\064\237\246\236\064" ; 23, 22, 42, 96, 228, "23:22:42.096228", "\016\095\038\138\033\140\244\064" ; 11, 27, 34, 989, 277, "11:27:34.989277", "\054\061\040\168\223\036\228\064" ; 3, 17, 2, 381, 105, "03:17:02.381105", "\171\115\012\200\048\023\199\064" ; 18, 22, 23, 399, 510, "18:22:23.399510", "\007\153\100\100\246\037\240\064" ; 11, 21, 24, 195, 329, "11:21:24.195329", "\095\154\034\064\134\246\227\064" ; 6, 25, 4, 393, 419, "06:25:04.393419", "\168\226\198\045\025\144\214\064" ; 1, 9, 52, 839, 306, "01:09:52.839306", "\086\013\194\220\214\096\176\064" ; 6, 30, 21, 219, 962, "06:30:21.219962", "\023\127\219\019\078\223\214\064" ; 6, 10, 26, 863, 842, "06:10:26.863842", "\187\244\047\073\183\180\213\064" ; 1, 41, 54, 561, 930, "01:41:54.561930", "\164\252\164\218\143\226\183\064" ; 1, 15, 45, 113, 374, "01:15:45.113374", "\056\022\020\006\029\193\177\064" ; 13, 44, 5, 681, 248, "13:44:05.681248", "\014\155\200\204\181\036\232\064" ; 15, 21, 15, 186, 950, "15:21:15.186950", "\000\145\126\251\101\253\234\064" ; 1, 3, 39, 804, 312, "01:03:39.804312", "\144\079\200\206\155\215\173\064" ; 17, 12, 33, 999, 334, "17:12:33.999334", "\249\075\139\250\063\064\238\064" ; 17, 4, 40, 962, 185, "17:04:40.962185", "\118\050\056\202\030\005\238\064" ; 9, 34, 34, 297, 322, "09:34:34.297322", "\076\109\169\131\073\213\224\064" ; 15, 57, 56, 468, 782, "15:57:56.468782", "\223\027\067\000\143\016\236\064" ; 4, 5, 59, 327, 480, "04:05:59.327480", "\012\089\221\234\169\211\204\064" ; 22, 41, 31, 211, 118, "22:41:31.211118", "\153\068\189\096\179\241\243\064" ; 3, 25, 58, 702, 337, "03:25:58.702337", "\226\198\045\230\089\035\200\064" ; 6, 0, 47, 333, 897, "06:00:47.333897", "\207\133\145\094\213\035\213\064" ; 0, 54, 21, 519, 110, "00:54:21.519110", "\013\050\201\200\009\123\169\064" ; 18, 51, 13, 728, 43, "18:51:13.728043", "\177\106\016\166\027\146\240\064" ; 4, 29, 44, 429, 234, "04:29:44.429234", "\042\196\035\241\054\156\207\064" ; 10, 13, 10, 233, 48, "10:13:10.233048", "\077\020\033\117\199\246\225\064" ; 20, 55, 34, 502, 837, "20:55:34.502837", "\099\207\158\011\104\100\242\064" ; 4, 53, 59, 694, 650, "04:53:59.694650", "\011\070\037\117\236\057\209\064" ; 16, 32, 52, 458, 263, "16:32:52.458263", "\191\042\023\170\142\022\237\064" ; 18, 59, 29, 768, 719, "18:59:29.768719", "\077\075\172\076\028\177\240\064" ; 13, 8, 44, 950, 875, "13:08:44.950875", "\114\104\145\109\158\027\231\064" ; 18, 26, 36, 406, 758, "18:26:36.406758", "\054\173\020\130\198\053\240\064" ; 8, 53, 35, 606, 65, "08:53:35.606065", "\144\218\196\201\230\067\223\064" ; 20, 58, 4, 20, 148, "20:58:04.020148", "\146\181\134\082\192\109\242\064" ; 16, 2, 47, 435, 553, "16:02:47.435553", "\085\216\012\240\237\052\236\064" ; 21, 26, 41, 412, 63, "21:26:41.412063", "\078\095\207\151\022\217\242\064" ; 16, 9, 0, 857, 643, "16:09:00.857643", "\149\187\207\113\155\099\236\064" ; 4, 25, 23, 443, 831, "04:25:23.443831", "\249\070\116\207\184\025\207\064" ; 23, 58, 46, 499, 702, "23:58:46.499702", "\060\134\199\254\103\019\245\064" ; 18, 38, 52, 325, 120, "18:38:52.325120", "\116\007\177\051\197\099\240\064" ; 0, 58, 11, 723, 774, "00:58:11.723774", "\100\119\129\146\114\071\171\064" ; 4, 12, 47, 952, 185, "04:12:47.952185", "\095\181\050\225\249\159\205\064" ; 9, 51, 16, 613, 520, "09:51:16.613520", "\238\177\244\161\147\082\225\064" ; 2, 50, 46, 396, 169, "02:50:46.396169", "\089\113\170\181\050\003\196\064" ; 19, 17, 15, 575, 290, "19:17:15.575290", "\123\073\099\052\185\243\240\064" ; 11, 44, 3, 135, 477, "11:44:03.135477", "\140\220\211\085\100\160\228\064" ; 0, 11, 12, 814, 745, "00:11:12.814745", "\163\204\006\153\132\006\133\064" ; 12, 15, 5, 312, 502, "12:15:05.312502", "\190\049\004\000\042\137\229\064" ; 6, 19, 38, 473, 992, "06:19:38.473992", "\165\138\226\085\158\062\214\064" ; 13, 12, 26, 345, 88, "13:12:26.345088", "\072\253\245\010\075\055\231\064" ; 2, 0, 44, 697, 12, "02:00:44.697012", "\236\224\096\111\178\076\188\064" ; 18, 1, 38, 269, 578, "18:01:38.269578", "\183\010\098\160\072\176\239\064" ; 13, 2, 33, 998, 651, "13:02:33.998651", "\036\241\242\244\063\237\230\064" ; 15, 10, 17, 287, 519, "15:10:17.287519", "\191\011\091\051\041\171\234\064" ; 2, 49, 56, 519, 795, "02:49:56.519795", "\208\126\164\136\066\234\195\064" ; 8, 14, 12, 778, 614, "08:14:12.778614", "\141\208\207\212\049\245\220\064" ; 4, 40, 28, 790, 154, "04:40:28.790154", "\052\021\226\145\050\111\208\064" ; 2, 3, 15, 465, 758, "02:03:15.465758", "\218\145\234\059\119\227\188\064" ; 14, 43, 32, 35, 982, "14:43:32.035982", "\040\185\195\038\129\226\233\064" ; 23, 17, 28, 780, 796, "23:17:28.780796", "\077\242\035\126\140\120\244\064" ; 13, 16, 34, 816, 46, "13:16:34.816046", "\065\128\012\029\090\086\231\064" ; 12, 1, 28, 131, 476, "12:01:28.131476", "\007\040\013\053\004\035\229\064" ; 21, 28, 6, 719, 536, "21:28:06.719536", "\069\046\056\131\107\222\242\064" ; 22, 3, 40, 265, 857, "22:03:40.265857", "\007\069\243\064\196\099\243\064" ; 15, 43, 21, 46, 683, "15:43:21.046683", "\201\088\109\126\033\163\235\064" ; 23, 15, 51, 725, 673, "23:15:51.725673", "\170\074\091\156\123\114\244\064" ; 1, 39, 58, 870, 273, "01:39:58.870273", "\151\025\054\202\222\110\183\064" ; 8, 33, 7, 638, 50, "08:33:07.638050", "\205\170\207\213\232\016\222\064" ; 22, 48, 57, 784, 209, "22:48:57.784209", "\132\188\030\140\156\013\244\064" ; 19, 53, 14, 612, 825, "19:53:14.612825", "\082\150\033\206\169\122\241\064" ; 15, 59, 18, 435, 884, "15:59:18.435884", "\155\000\195\242\205\026\236\064" ; 2, 25, 49, 847, 788, "02:25:49.847788", "\248\050\081\132\236\022\193\064" ; 20, 26, 48, 479, 693, "20:26:48.479693", "\050\145\210\172\135\248\241\064" ; 10, 56, 11, 403, 350, "10:56:11.403350", "\091\066\062\232\108\057\227\064" ; 19, 30, 13, 794, 52, "19:30:13.794052", "\181\222\111\180\092\036\241\064" ; 9, 52, 31, 178, 475, "09:52:31.178475", "\005\052\017\182\229\091\225\064" ; 4, 41, 35, 534, 241, "04:41:35.534241", "\204\041\001\049\226\127\208\064" ; 9, 59, 56, 4, 722, "09:59:56.004722", "\114\192\174\038\128\147\225\064" ; 23, 39, 1, 746, 574, "23:39:01.746574", "\033\148\247\241\091\201\244\064" ; 18, 47, 1, 310, 9, "18:47:01.310009", "\071\255\203\245\084\130\240\064" ; 17, 2, 12, 858, 376, "17:02:12.858376", "\246\241\208\119\155\242\237\064" ; 12, 16, 9, 650, 171, "12:16:09.650171", "\186\105\051\206\052\145\229\064" ; 22, 39, 49, 662, 796, "22:39:49.662796", "\126\250\207\154\090\235\243\064" ; 9, 58, 27, 229, 503, "09:58:27.229503", "\235\172\022\088\103\136\225\064" ; 19, 11, 14, 997, 82, "19:11:14.997082", "\087\065\012\244\047\221\240\064" ; 7, 27, 44, 968, 527, "07:27:44.968527", "\147\171\088\252\061\060\218\064" ; 22, 3, 29, 149, 503, "22:03:29.149503", "\251\065\093\100\018\099\243\064" ; 19, 11, 21, 861, 829, "19:11:21.861829", "\156\052\013\202\157\221\240\064" ; 12, 47, 38, 959, 340, "12:47:38.959340", "\184\204\233\178\094\125\230\064" ; 19, 9, 52, 551, 811, "19:09:52.551811", "\106\197\055\212\008\216\240\064" ; 13, 16, 32, 167, 947, "13:16:32.167947", "\015\099\210\095\005\086\231\064" ; 20, 2, 57, 993, 246, "20:02:57.993246", "\238\234\085\228\031\159\241\064" ; 5, 57, 54, 63, 560, "05:57:54.063560", "\085\246\093\017\132\248\212\064" ; 23, 42, 28, 968, 416, "23:42:28.968416", "\142\198\161\126\079\214\244\064" ; 9, 32, 1, 209, 51, "09:32:01.209051", "\007\185\139\176\038\194\224\064" ; 4, 37, 12, 353, 793, "04:37:12.353793", "\035\101\139\164\022\062\208\064" ; 14, 16, 24, 22, 564, "14:16:24.022564", "\066\035\216\184\000\023\233\064" ; 0, 36, 58, 604, 546, "00:36:58.604546", "\219\165\013\135\053\085\161\064" ; 19, 31, 27, 107, 152, "19:31:27.107152", "\251\003\229\182\241\040\241\064" ; 15, 20, 28, 730, 581, "15:20:28.730581", "\195\103\235\096\151\247\234\064" ; 3, 35, 0, 416, 331, "03:35:00.416331", "\167\142\085\074\053\050\201\064" ; 16, 40, 35, 5, 228, "16:40:35.005228", "\032\233\211\042\096\080\237\064" ; 13, 49, 32, 488, 174, "13:49:32.488174", "\152\020\031\159\143\077\232\064" ; 12, 6, 54, 517, 278, "12:06:54.517278", "\158\151\138\141\208\075\229\064" ; 10, 58, 4, 539, 472, "10:58:04.539472", "\163\200\090\067\145\071\227\064" ; 2, 24, 1, 578, 173, "02:24:01.578173", "\055\167\146\001\202\224\192\064" ; 16, 57, 50, 777, 622, "16:57:50.777622", "\085\136\071\226\216\209\237\064" ; 16, 53, 46, 601, 128, "16:53:46.601128", "\151\201\112\060\083\179\237\064" ; 15, 20, 18, 852, 855, "15:20:18.852855", "\167\145\150\074\091\246\234\064" ; 18, 12, 59, 635, 486, "18:12:59.635486", "\049\094\243\042\186\002\240\064" ; 12, 6, 2, 534, 701, "12:06:02.534701", "\132\069\069\028\081\069\229\064" ; 7, 16, 46, 314, 712, "07:16:46.314712", "\234\204\061\036\148\151\217\064" ; 9, 32, 10, 819, 747, "09:32:10.819747", "\128\015\094\059\090\195\224\064" ; 10, 30, 38, 940, 279, "10:30:38.940279", "\068\252\195\022\222\121\226\064" ; 20, 33, 2, 955, 226, "20:33:02.955226", "\229\014\155\072\239\015\242\064" ; 16, 30, 50, 833, 468, "16:30:50.833468", "\072\021\197\171\090\007\237\064" ; 21, 17, 36, 261, 82, "21:17:36.261082", "\185\081\100\045\004\183\242\064" ; 13, 4, 53, 826, 241, "13:04:53.826241", "\052\247\144\112\186\254\230\064" ; 6, 44, 53, 990, 515, "06:44:53.990515", "\205\006\153\100\127\185\215\064" ; 0, 55, 6, 193, 784, "00:55:06.193784", "\250\012\168\055\099\212\169\064" ; 19, 28, 41, 622, 72, "19:28:41.622072", "\252\196\001\244\153\030\241\064" ; 10, 18, 58, 713, 107, "10:18:58.713107", "\114\197\197\209\086\034\226\064" ; 20, 28, 59, 330, 19, "20:28:59.330019", "\193\000\194\071\181\000\242\064" ; 3, 14, 36, 755, 715, "03:14:36.755715", "\012\229\068\187\096\206\198\064" ; 2, 24, 28, 853, 475, "02:24:28.853475", "\122\054\171\062\109\238\192\064" ; 1, 25, 3, 40, 808, "01:25:03.040808", "\106\161\100\114\010\239\179\064" ; 4, 3, 27, 784, 610, "04:03:27.784610", "\014\185\025\110\228\135\204\064" ; 7, 44, 16, 435, 559, "07:44:16.435559", "\031\219\050\224\027\052\219\064" ; 8, 55, 29, 535, 121, "08:55:29.535121", "\154\038\108\063\098\096\223\064" ; 2, 37, 19, 254, 513, "02:37:19.254513", "\181\201\225\147\160\111\194\064" ; 13, 48, 33, 542, 623, "13:48:33.542623", "\226\232\042\093\049\070\232\064" ; 0, 31, 26, 169, 909, "00:31:26.169909", "\048\249\159\252\173\120\157\064" ; 19, 33, 21, 808, 356, "19:33:21.808356", "\121\179\006\239\028\048\241\064" ; 9, 56, 11, 510, 103, "09:56:11.510103", "\211\134\195\082\112\119\225\064" ; 22, 15, 53, 447, 277, "22:15:53.447277", "\116\237\011\040\151\145\243\064" ; 7, 47, 18, 652, 817, "07:47:18.652817", "\081\244\192\199\169\097\219\064" ; 13, 31, 25, 358, 201, "13:31:25.358201", "\141\241\097\118\171\197\231\064" ; 21, 20, 16, 817, 1, "21:20:16.817001", "\252\163\111\018\013\193\242\064" ; 6, 32, 45, 652, 569, "06:32:45.652569", "\088\196\176\195\105\003\215\064" ; 15, 22, 15, 389, 236, "15:22:15.389236", "\078\014\159\116\236\004\235\064" ; 16, 16, 36, 720, 181, "16:16:36.720181", "\071\006\185\011\151\156\236\064" ; 22, 54, 51, 674, 152, "22:54:51.674152", "\136\155\083\201\186\035\244\064" ; 5, 28, 24, 175, 572, "05:28:24.175572", "\134\087\146\060\011\062\211\064" ; 13, 17, 47, 496, 804, "13:17:47.496804", "\145\128\209\229\111\095\231\064" ; 4, 20, 26, 254, 37, "04:20:26.254037", "\125\207\072\132\032\133\206\064" ; 3, 4, 45, 241, 504, "03:04:45.241504", "\237\098\154\233\158\166\197\064" ; 10, 30, 1, 72, 903, "10:30:01.072903", "\025\172\056\085\034\117\226\064" ; 3, 2, 12, 632, 422, "03:02:12.632422", "\162\063\052\243\080\090\197\064" ; 9, 48, 4, 525, 547, "09:48:04.525547", "\049\241\071\209\144\058\225\064" ; 5, 33, 48, 617, 733, "05:33:48.617733", "\042\254\239\136\039\143\211\064" ; 13, 20, 51, 704, 95, "13:20:51.704095", "\201\060\242\135\118\118\231\064" ; 15, 16, 49, 141, 358, "15:16:49.141358", "\097\054\001\134\036\220\234\064" ; 10, 5, 54, 235, 125, "10:05:54.235125", "\047\221\036\134\071\192\225\064" ; 15, 39, 1, 683, 642, "15:39:01.683642", "\005\048\101\224\181\130\235\064" ; 22, 23, 35, 8, 726, "22:23:35.008726", "\202\223\189\035\112\174\243\064" ; 19, 50, 10, 184, 265, "19:50:10.184265", "\076\219\191\242\034\111\241\064" ; 14, 53, 9, 455, 424, "14:53:09.455424", "\058\090\213\146\174\042\234\064" ; 14, 27, 20, 102, 659, "14:27:20.102659", "\244\134\251\072\003\105\233\064" ; 5, 23, 13, 429, 953, "05:23:13.429953", "\116\150\089\132\091\240\210\064" ; 13, 26, 55, 977, 960, "13:26:55.977960", "\025\197\114\075\255\163\231\064" ; 17, 33, 34, 748, 866, "17:33:34.748866", "\099\212\181\246\215\221\238\064" ; 11, 26, 13, 189, 610, "11:26:13.189610", "\160\253\072\017\166\026\228\064" ; 7, 40, 12, 699, 729, "07:40:12.699729", "\196\036\092\200\044\247\218\064" ; 3, 20, 55, 14, 766, "03:20:55.014766", "\139\047\218\227\129\139\199\064" ; 23, 52, 40, 972, 555, "23:52:40.972555", "\233\212\149\143\143\252\244\064" ; 1, 7, 44, 694, 383, "01:07:44.694383", "\204\039\043\134\099\193\175\064" ; 17, 36, 6, 739, 732, "17:36:06.739732", "\122\113\226\171\215\240\238\064" ; 6, 3, 7, 967, 641, "06:03:07.967641", "\081\132\212\237\253\070\213\064" ; 19, 11, 45, 731, 856, "19:11:45.731856", "\022\163\174\181\027\223\240\064" ; 8, 12, 33, 94, 129, "08:12:33.094129", "\039\164\053\006\070\220\220\064" ; 11, 49, 26, 634, 635, "11:49:26.634635", "\060\015\238\078\212\200\228\064" ; 20, 42, 8, 30, 441, "20:42:08.030441", "\183\179\175\124\000\050\242\064" ; 6, 59, 18, 16, 678, "06:59:18.016678", "\036\154\064\017\129\145\216\064" ; 2, 25, 50, 981, 574, "02:25:50.981574", "\077\130\055\164\125\023\193\064" ; 14, 36, 13, 985, 140, "14:36:13.985140", "\063\082\068\134\191\171\233\064" ; 17, 41, 40, 642, 943, "17:41:40.642943", "\198\050\253\146\148\026\239\064" ; 9, 57, 3, 34, 126, "09:57:03.034126", "\190\104\143\023\225\125\225\064" ; 17, 53, 38, 798, 380, "17:53:38.798380", "\185\054\084\140\089\116\239\064" ; 18, 22, 3, 741, 80, "18:22:03.741080", "\187\179\118\219\187\036\240\064" ; 6, 25, 9, 532, 945, "06:25:09.532945", "\100\088\197\027\098\145\214\064" ; 13, 55, 56, 614, 870, "13:55:56.614870", "\170\217\003\173\147\125\232\064" ; 2, 55, 20, 655, 126, "02:55:20.655126", "\098\052\043\219\083\140\196\064" ; 1, 44, 0, 834, 449, "01:44:00.834449", "\046\029\115\158\213\096\184\064" ; 20, 14, 7, 719, 453, "20:14:07.719453", "\032\038\225\130\251\200\241\064" ; 17, 37, 18, 206, 171, "17:37:18.206171", "\204\236\243\152\198\249\238\064" ; 20, 3, 44, 678, 946, "20:03:44.678946", "\028\123\246\220\010\162\241\064" ; 22, 16, 42, 340, 782, "22:16:42.340782", "\145\211\215\115\165\148\243\064" ; 6, 50, 34, 107, 455, "06:50:34.107455", "\179\239\138\224\134\014\216\064" ; 19, 17, 46, 638, 480, "19:17:46.638480", "\243\205\054\055\170\245\240\064" ; 5, 4, 33, 844, 242, "05:04:33.844242", "\250\152\015\008\118\216\209\064" ; 13, 10, 27, 455, 445, "13:10:27.455445", "\132\100\001\147\110\040\231\064" ; 13, 40, 52, 299, 509, "13:40:52.299509", "\251\229\147\149\137\012\232\064" ; 15, 25, 27, 366, 989, "15:25:27.366989", "\032\183\095\190\235\028\235\064" ; 4, 28, 2, 127, 267, "04:28:02.127267", "\110\249\072\074\016\105\207\064" ; 1, 36, 30, 510, 866, "01:36:30.510866", "\164\058\029\200\130\158\182\064" ; 3, 47, 17, 771, 196, "03:47:17.771196", "\104\239\140\182\226\162\202\064" ; 12, 14, 23, 893, 724, "12:14:23.893724", "\244\018\099\153\252\131\229\064" ; 3, 2, 49, 697, 101, "03:02:49.697101", "\129\006\155\058\217\108\197\064" ; 1, 58, 8, 646, 87, "01:58:08.646087", "\095\039\245\101\165\176\187\064" ; 4, 53, 45, 548, 252, "04:53:45.548252", "\126\142\143\022\099\054\209\064" ; 13, 59, 25, 490, 312, "13:59:25.490312", "\154\202\162\176\175\151\232\064" ; 15, 1, 1, 851, 781, "15:01:01.851781", "\076\058\202\065\187\101\234\064" ; 9, 0, 30, 340, 99, "09:00:30.340099", "\154\152\046\196\149\171\223\064" ; 19, 29, 19, 357, 372, "19:29:19.357372", "\200\179\203\183\245\032\241\064" ; 17, 1, 20, 401, 181, "17:01:20.401181", "\089\137\121\214\012\236\237\064" ; 10, 3, 20, 424, 56, "10:03:20.424056", "\117\227\221\145\013\173\225\064" ; 16, 7, 0, 5, 773, "16:07:00.005773", "\198\219\074\047\128\084\236\064" ; 6, 7, 52, 968, 122, "06:07:52.968122", "\035\250\181\245\061\142\213\064" ; 5, 47, 4, 905, 809, "05:47:04.905809", "\219\079\198\248\057\086\212\064" ; 15, 52, 38, 390, 142, "15:52:38.390142", "\089\019\011\124\204\232\235\064" ; 13, 42, 25, 293, 2, "13:42:25.293002", "\245\186\069\096\041\024\232\064" ; 10, 12, 43, 965, 79, "10:12:43.965079", "\225\090\237\225\126\243\225\064" ; 3, 22, 20, 576, 968, "03:22:20.576968", "\107\097\022\218\073\182\199\064" ; 9, 0, 9, 220, 310, "09:00:09.220310", "\063\029\143\025\078\166\223\064" ; 18, 1, 2, 567, 819, "18:01:02.567819", "\098\192\146\043\210\171\239\064" ; 18, 47, 46, 900, 154, "18:47:46.900154", "\117\225\007\103\046\133\240\064" ; 8, 41, 14, 635, 546, "08:41:14.635546", "\070\033\201\172\168\138\222\064" ; 6, 31, 9, 845, 244, "06:31:09.845244", "\073\074\122\024\118\235\214\064" ; 5, 35, 37, 599, 126, "05:35:37.599126", "\011\148\020\088\102\170\211\064" ; 2, 59, 13, 237, 63, "02:59:13.237063", "\011\148\020\088\158\000\197\064" ; 23, 42, 17, 867, 96, "23:42:17.867096", "\040\014\160\223\157\213\244\064" ; 5, 22, 48, 110, 741, "05:22:48.110741", "\085\107\097\022\007\234\210\064" ; 21, 40, 51, 603, 273, "21:40:51.603273", "\217\150\001\167\057\014\243\064" ; 11, 31, 0, 580, 306, "11:31:00.580306", "\118\227\221\145\146\062\228\064" ; 22, 48, 8, 980, 879, "22:48:08.980879", "\165\045\174\177\143\010\244\064" ; 1, 37, 0, 77, 660, "01:37:00.077660", "\053\152\134\225\019\188\182\064" ; 1, 47, 29, 10, 901, "01:47:29.010901", "\127\110\104\202\002\049\185\064" ; 19, 54, 7, 54, 168, "19:54:07.054168", "\200\067\223\221\240\125\241\064" ; 0, 10, 35, 247, 798, "00:10:35.247798", "\029\144\132\125\251\217\131\064" ; 9, 24, 1, 568, 656, "09:24:01.568656", "\085\017\110\050\050\134\224\064" ; 2, 28, 58, 126, 632, "02:28:58.126632", "\080\053\122\053\016\117\193\064" ; 8, 52, 47, 629, 211, "08:52:47.629211", "\210\054\254\068\232\055\223\064" ; 13, 38, 23, 40, 802, "13:38:23.040802", "\244\254\063\078\225\249\231\064" ; 2, 4, 55, 583, 109, "02:04:55.583109", "\000\165\161\070\149\071\189\064" ; 18, 33, 24, 412, 679, "18:33:24.412679", "\140\075\085\154\070\079\240\064" ; 7, 3, 11, 775, 52, "07:03:11.775052", "\045\180\115\154\241\203\216\064" ; 23, 54, 20, 732, 269, "23:54:20.732269", "\238\178\095\183\203\002\245\064" ; 20, 23, 22, 578, 122, "20:23:22.578122", "\177\218\252\063\169\235\241\064" ; 1, 43, 35, 961, 599, "01:43:35.961599", "\222\032\090\043\246\071\184\064" ; 9, 38, 6, 681, 168, "09:38:06.681168", "\098\213\032\204\213\239\224\064" ; 22, 2, 53, 977, 794, "22:02:53.977794", "\068\082\011\165\223\096\243\064" ; 4, 39, 45, 514, 357, "04:39:45.514357", "\094\159\057\235\096\100\208\064" ; 12, 12, 16, 240, 164, "12:12:16.240164", "\181\105\108\175\007\116\229\064" ; 7, 26, 36, 913, 354, "07:26:36.913354", "\235\085\100\116\058\043\218\064" ; 5, 7, 28, 37, 669, "05:07:28.037669", "\197\060\043\105\002\004\210\064" ; 14, 25, 26, 907, 108, "14:25:26.907108", "\062\091\007\007\221\090\233\064" ; 3, 22, 18, 432, 188, "03:22:18.432188", "\221\182\239\081\055\181\199\064" ; 20, 21, 43, 856, 915, "20:21:43.856915", "\199\128\236\181\125\229\241\064" ; 18, 36, 2, 89, 71, "18:36:02.089071", "\129\182\213\108\033\089\240\064" ; 3, 45, 27, 143, 62, "03:45:27.143062", "\166\009\219\079\146\107\202\064" ; 5, 42, 46, 799, 835, "05:42:46.799835", "\204\035\127\048\179\021\212\064" ; 20, 50, 50, 775, 868, "20:50:50.775868", "\096\144\244\105\172\082\242\064" ; 11, 46, 48, 138, 441, "11:46:48.138441", "\237\209\027\110\004\181\228\064" ; 8, 7, 38, 624, 880, "08:07:38.624880", "\251\174\008\254\167\146\220\064" ; 11, 7, 4, 242, 674, "11:07:04.242674", "\179\067\252\195\007\139\227\064" ; 11, 7, 6, 247, 737, "11:07:06.247737", "\033\037\118\237\071\139\227\064" ; 23, 25, 50, 608, 614, "23:25:50.608614", "\158\008\226\188\233\151\244\064" ; 5, 39, 56, 784, 251, "05:39:56.784251", "\055\027\043\049\050\235\211\064" ; 19, 10, 45, 822, 685, "19:10:45.822685", "\031\191\183\041\093\219\240\064" ; 21, 5, 45, 554, 925, "21:05:45.554925", "\108\009\249\224\152\138\242\064" ; 7, 26, 11, 165, 949, "07:26:11.165949", "\244\141\232\158\202\036\218\064" ; 0, 4, 20, 834, 422, "00:04:20.834422", "\002\017\226\202\089\077\112\064" ; 8, 56, 8, 981, 454, "08:56:08.981454", "\034\112\036\208\062\106\223\064" ; 21, 42, 27, 910, 605, "21:42:27.910605", "\105\140\214\145\062\020\243\064" ; 11, 44, 6, 316, 799, "11:44:06.316799", "\013\168\055\035\202\160\228\064" ; 4, 46, 27, 996, 225, "04:46:27.996225", "\157\128\038\194\255\200\208\064" ; 19, 19, 49, 859, 689, "19:19:49.859689", "\187\064\073\193\093\253\240\064" ; 14, 5, 54, 669, 467, "14:05:54.669467", "\216\014\070\108\085\200\232\064" ; 18, 13, 43, 269, 148, "18:13:43.269148", "\029\034\110\078\116\005\240\064" ; 2, 59, 37, 282, 481, "02:59:37.282481", "\094\096\086\040\164\012\197\064" ; 3, 15, 48, 795, 581, "03:15:48.795581", "\041\036\153\213\101\242\198\064" ; 9, 50, 48, 299, 261, "09:50:48.299261", "\255\205\139\147\009\079\225\064" ; 2, 25, 16, 976, 957, "02:25:16.976957", "\077\078\237\012\125\006\193\064" ; 18, 30, 56, 115, 121, "18:30:56.115121", "\034\030\137\215\001\070\240\064" ; 1, 44, 39, 392, 37, "01:44:39.392037", "\210\109\137\092\100\135\184\064" ; 17, 16, 26, 419, 986, "17:16:26.419986", "\217\122\134\112\077\093\238\064" ; 12, 36, 16, 661, 134, "12:36:16.661134", "\137\125\002\040\021\040\230\064" ; 4, 21, 18, 626, 394, "04:21:18.626394", "\053\184\173\045\080\159\206\064" ; 11, 48, 3, 9, 745, "11:48:03.009745", "\009\191\212\079\096\190\228\064" ; 13, 1, 14, 99, 360, "13:01:14.099360", "\209\005\245\045\067\227\230\064" ; 7, 42, 59, 586, 892, "07:42:59.586892", "\146\118\163\143\229\032\219\064" ; 22, 15, 19, 894, 464, "22:15:19.894464", "\183\123\185\079\126\143\243\064" ; 9, 29, 53, 476, 627, "09:29:53.476627", "\045\068\135\064\047\178\224\064" ; 4, 57, 46, 422, 906, "04:57:46.422906", "\210\083\228\016\155\114\209\064" ; 5, 27, 50, 606, 630, "05:27:50.606630", "\177\162\006\211\166\053\211\064" ; 4, 21, 49, 565, 582, "04:21:49.565582", "\155\176\253\100\200\174\206\064" ; 2, 45, 3, 232, 906, "02:45:03.232906", "\133\034\221\207\157\087\195\064" ; 19, 19, 47, 935, 299, "19:19:47.935299", "\144\021\252\246\062\253\240\064" ; 7, 55, 59, 576, 131, "07:55:59.576131", "\206\142\084\223\228\227\219\064" ; 11, 28, 8, 394, 379, "11:28:08.394379", "\103\181\192\158\012\041\228\064" ; 1, 59, 43, 310, 177, "01:59:43.310177", "\249\134\194\103\079\015\188\064" ; 15, 5, 47, 536, 540, "15:05:47.536540", "\032\239\085\043\113\137\234\064" ; 19, 57, 17, 503, 589, "19:57:17.503589", "\218\086\179\014\216\137\241\064" ; 20, 34, 34, 102, 866, "20:34:34.102866", "\158\209\086\165\161\021\242\064" ; 10, 42, 59, 160, 49, "10:42:59.160049", "\153\020\031\031\101\214\226\064" ; 11, 8, 59, 578, 822, "11:08:59.578822", "\007\183\181\133\114\153\227\064" ; 3, 17, 31, 50, 827, "03:17:31.050827", "\096\199\127\129\134\037\199\064" ; 12, 30, 55, 258, 676, "12:30:55.258676", "\009\228\018\071\232\255\229\064" ; 19, 13, 7, 159, 780, "19:13:07.159780", "\041\121\117\142\050\228\240\064" ; 23, 40, 19, 742, 644, "23:40:19.742644", "\201\172\222\225\059\206\244\064" ; 21, 33, 45, 918, 214, "21:33:45.918214", "\204\041\001\177\158\243\242\064" ; 20, 11, 48, 801, 254, "20:11:48.801254", "\221\182\239\209\076\192\241\064" ; 16, 9, 33, 673, 213, "16:09:33.673213", "\072\253\245\138\181\103\236\064" ; 10, 8, 25, 449, 522, "10:08:25.449522", "\027\246\123\098\046\211\225\064" ; 10, 21, 55, 678, 677, "10:21:55.678677", "\242\211\184\183\117\056\226\064" ; 7, 30, 15, 946, 45, "07:30:15.946045", "\227\083\000\140\252\097\218\064" ; 19, 42, 25, 890, 820, "19:42:25.890820", "\234\120\204\064\030\082\241\064" ; 10, 30, 39, 878, 64, "10:30:39.878064", "\121\172\025\025\252\121\226\064" ; 22, 6, 37, 752, 922, "22:06:37.752922", "\103\240\247\011\220\110\243\064" ; 4, 26, 5, 965, 134, "04:26:05.965134", "\033\203\130\137\251\046\207\064" ; 23, 44, 24, 516, 894, "23:44:24.516894", "\152\164\050\069\136\221\244\064" ; 12, 13, 47, 585, 146, "12:13:47.585146", "\172\026\132\185\114\127\229\064" ; 4, 45, 37, 21, 297, "04:45:37.021297", "\160\023\238\092\065\188\208\064" ; 19, 39, 3, 816, 798, "19:39:03.816798", "\151\199\154\017\125\069\241\064" ; 22, 19, 23, 93, 30, "22:19:23.093030", "\120\006\013\125\177\158\243\064" ; 9, 47, 24, 765, 676, "09:47:24.765676", "\107\244\106\128\152\053\225\064" ; 17, 5, 52, 312, 597, "17:05:52.312597", "\122\108\203\000\010\014\238\064" ; 10, 27, 50, 581, 757, "10:27:50.581757", "\039\219\192\157\210\100\226\064" ; 11, 17, 34, 181, 361, "11:17:34.181361", "\120\149\181\205\197\217\227\064" ; 5, 28, 27, 632, 204, "05:28:27.632204", "\026\196\007\118\232\062\211\064" ; 4, 6, 18, 846, 38, "04:06:18.846038", "\150\034\249\074\108\221\204\064" ; 21, 20, 55, 313, 369, "21:20:55.313369", "\105\054\143\003\117\195\242\064" ; 12, 47, 20, 562, 161, "12:47:20.562161", "\195\016\057\253\017\123\230\064" ; 5, 39, 9, 596, 572, "05:39:09.596572", "\110\083\060\046\102\223\211\064" ; 7, 48, 21, 162, 319, "07:48:21.162319", "\033\059\111\099\074\113\219\064" ; 10, 22, 10, 353, 413, "10:22:10.353413", "\160\199\040\079\075\058\226\064" ; 8, 35, 18, 526, 294, "08:35:18.526294", "\134\007\205\174\161\049\222\064" ; 11, 10, 5, 872, 891, "11:10:05.872891", "\064\027\185\238\187\161\227\064" ; 5, 33, 12, 831, 542, "05:33:12.831542", "\208\239\251\055\053\134\211\064" ; 15, 14, 26, 55, 411, "15:14:26.055411", "\027\074\237\197\065\202\234\064" ; 12, 13, 49, 568, 340, "12:13:49.568340", "\032\094\215\047\178\127\229\064" ; 3, 45, 53, 700, 832, "03:45:53.700832", "\255\235\220\180\217\120\202\064" ; 3, 32, 0, 445, 105, "03:32:00.445105", "\036\093\051\249\056\216\200\064" ; 16, 51, 54, 237, 975, "16:51:54.237975", "\073\191\125\157\071\165\237\064" ; 1, 38, 11, 455, 556, "01:38:11.455556", "\127\105\081\159\116\003\183\064" ; 17, 33, 31, 486, 138, "17:33:31.486138", "\107\071\113\142\111\221\238\064" ; 12, 31, 7, 839, 703, "12:31:07.839703", "\107\211\216\222\122\001\230\064" ; 0, 4, 45, 554, 696, "00:04:45.554696", "\141\179\233\008\224\216\113\064" ; 3, 34, 52, 940, 384, "03:34:52.940384", "\216\190\128\094\120\046\201\064" ; 15, 25, 15, 950, 191, "15:25:15.950191", "\190\244\246\103\126\027\235\064" ; 1, 14, 52, 429, 750, "01:14:52.429750", "\117\147\024\004\110\140\177\064" ; 6, 34, 58, 874, 249, "06:34:58.874249", "\228\019\178\243\183\036\215\064" ; 1, 21, 43, 808, 145, "01:21:43.808145", "\109\057\151\226\206\039\179\064" ; 12, 16, 39, 863, 458, "12:16:39.863458", "\239\171\114\161\251\148\229\064" ; 1, 8, 47, 537, 905, "01:08:47.537905", "\091\095\036\180\137\031\176\064" ; 6, 41, 13, 165, 603, "06:41:13.165603", "\072\083\061\153\074\130\215\064" ; 2, 52, 19, 451, 21, "02:52:19.451021", "\103\094\014\187\185\049\196\064" ; 4, 44, 38, 957, 87, "04:44:38.957087", "\027\213\233\064\189\173\208\064" ; 22, 25, 34, 319, 443, "22:25:34.319443", "\095\067\112\028\229\181\243\064" ; 2, 0, 9, 468, 516, "02:00:09.468516", "\167\033\170\240\119\041\188\064" ; 17, 33, 55, 261, 263, "17:33:55.261263", "\021\057\068\092\104\224\238\064" ; 22, 36, 51, 125, 364, "22:36:51.125364", "\130\174\125\001\050\224\243\064" ; 13, 57, 56, 294, 68, "13:57:56.294068", "\090\075\001\105\137\140\232\064" ; 7, 40, 44, 943, 876, "07:40:44.943876", "\222\225\118\104\060\255\218\064" ; 16, 4, 52, 997, 995, "16:04:52.997995", "\211\053\147\239\159\068\236\064" ; 5, 18, 7, 499, 329, "05:18:07.499329", "\060\159\001\245\223\163\210\064" ; 17, 38, 28, 112, 353, "17:38:28.112353", "\148\081\101\152\131\002\239\064" ; 21, 32, 14, 406, 140, "21:32:14.406140", "\026\168\140\127\230\237\242\064" ; 23, 43, 16, 785, 500, "23:43:16.785500", "\176\114\104\145\076\217\244\064" ; 8, 7, 51, 219, 473, "08:07:51.219473", "\087\123\216\011\206\149\220\064" ; 21, 38, 56, 604, 709, "21:38:56.604709", "\042\088\227\172\009\007\243\064" ; 0, 31, 46, 11, 952, "00:31:46.011952", "\125\036\037\061\012\200\157\064" ; 22, 4, 9, 587, 412, "22:04:09.587412", "\020\032\010\102\153\101\243\064" ; 0, 33, 2, 431, 551, "00:33:02.431551", "\058\094\129\232\185\249\158\064" ; 2, 59, 6, 244, 342, "02:59:06.244342", "\133\065\153\070\031\253\196\064" ; 18, 32, 14, 22, 622, "18:32:14.022622", "\227\226\168\092\224\074\240\064" ; 7, 0, 27, 634, 860, "07:00:27.634860", "\098\214\139\161\232\162\216\064" ; 20, 14, 50, 117, 775, "20:14:50.117775", "\212\009\104\226\161\203\241\064" ; 7, 39, 37, 581, 515, "07:39:37.581515", "\200\176\138\055\101\238\218\064" ; 15, 0, 37, 62, 758, "15:00:37.062758", "\178\016\029\002\162\098\234\064" ; 12, 27, 57, 558, 194, "12:27:57.558194", "\218\169\185\220\177\233\229\064" ; 18, 47, 43, 562, 468, "18:47:43.562468", "\017\114\222\255\248\132\240\064" ; 22, 9, 33, 192, 229, "22:09:33.192229", "\069\183\094\019\211\121\243\064" ; 9, 3, 59, 431, 871, "09:03:59.431871", "\070\067\198\163\219\223\223\064" ; 15, 43, 19, 108, 572, "15:43:19.108572", "\168\252\107\121\227\162\235\064" ; 16, 21, 23, 703, 779, "16:21:23.703779", "\148\137\091\133\118\192\236\064" ; 15, 27, 16, 457, 491, "15:27:16.457491", "\103\042\196\163\142\042\235\064" ; 6, 29, 26, 396, 890, "06:29:26.396890", "\135\080\165\102\153\209\214\064" ; 5, 57, 55, 162, 968, "05:57:55.162968", "\147\085\017\110\202\248\212\064" ; 16, 27, 55, 682, 785, "16:27:55.682785", "\166\237\095\217\117\241\236\064" ; 13, 17, 43, 926, 438, "13:17:43.926438", "\249\077\097\165\253\094\231\064" ; 0, 14, 23, 757, 78, "00:14:23.757078", "\043\020\233\126\014\254\138\064" ; 15, 15, 28, 862, 887, "15:15:28.862887", "\165\050\197\156\027\210\234\064" ; 7, 36, 40, 150, 61, "07:36:40.150061", "\218\115\153\154\009\194\218\064" ; 20, 14, 47, 331, 190, "20:14:47.331190", "\173\226\141\076\117\203\241\064" ; 19, 11, 53, 178, 8, "19:11:53.178008", "\167\234\030\217\146\223\240\064" ; 22, 24, 5, 950, 659, "22:24:05.950659", "\042\054\230\053\095\176\243\064" ; 17, 12, 0, 278, 440, "17:12:00.278440", "\189\000\251\232\008\060\238\064" ; 3, 30, 56, 630, 954, "03:30:56.630954", "\163\197\025\195\080\184\200\064" ; 3, 10, 47, 863, 191, "03:10:47.863191", "\153\237\010\125\238\091\198\064" ; 13, 36, 39, 943, 659, "13:36:39.943659", "\242\091\116\050\254\236\231\064" ; 16, 22, 6, 164, 672, "16:22:06.164672", "\210\054\254\068\197\197\236\064" ; 5, 18, 56, 611, 241, "05:18:56.611241", "\063\146\146\030\039\176\210\064" ; 7, 30, 17, 149, 797, "07:30:17.149797", "\003\040\070\150\073\098\218\064" ; 13, 51, 15, 55, 542, "13:51:15.055542", "\050\004\000\199\097\090\232\064" ; 1, 27, 20, 981, 114, "01:27:20.981114", "\166\127\073\042\251\120\180\064" ; 5, 59, 24, 7, 913, "05:59:24.007913", "\014\135\165\129\000\015\213\064" ; 6, 2, 9, 515, 66, "06:02:09.515066", "\082\098\215\246\096\056\213\064" ; 5, 56, 54, 339, 995, "05:56:54.339995", "\115\099\122\194\149\233\212\064" ; 8, 51, 4, 891, 456, "08:51:04.891456", "\117\119\157\013\057\030\223\064" ; 10, 32, 44, 880, 256, "10:32:44.880256", "\131\161\014\043\156\137\226\064" ; 12, 16, 22, 65, 6, "12:16:22.065006", "\130\118\135\020\194\146\229\064" ; 10, 0, 40, 776, 482, "10:00:40.776482", "\126\199\240\216\024\153\225\064" ; 21, 59, 34, 855, 20, "21:59:34.855020", "\151\115\041\174\109\084\243\064" ; 8, 11, 23, 625, 637, "08:11:23.625637", "\139\197\111\010\232\202\220\064" ; 13, 40, 39, 370, 59, "13:40:39.370059", "\211\248\133\215\235\010\232\064" ; 20, 40, 39, 415, 538, "20:40:39.415538", "\131\044\011\166\118\044\242\064" ; 2, 41, 42, 978, 281, "02:41:42.978281", "\166\210\079\056\125\243\194\064" ; 11, 50, 53, 136, 829, "11:50:53.136829", "\004\054\231\096\164\211\228\064" ; 9, 33, 2, 170, 187, "09:33:02.170187", "\230\001\044\114\197\201\224\064" ; 7, 18, 14, 54, 690, "07:18:14.054690", "\091\124\010\128\131\173\217\064" ; 2, 5, 40, 328, 732, "02:05:40.328732", "\039\197\199\039\084\116\189\064" ; 23, 28, 54, 876, 627, "23:28:54.876627", "\125\008\170\006\110\163\244\064" ; 9, 24, 2, 270, 315, "09:24:02.270315", "\147\164\107\166\072\134\224\064" ; 10, 38, 30, 8, 328, "10:38:30.008328", "\245\020\057\068\192\180\226\064" ; 18, 38, 26, 831, 230, "18:38:26.831230", "\024\212\183\076\045\098\240\064" ; 0, 1, 55, 347, 769, "00:01:55.347769", "\002\100\232\216\065\214\092\064" ; 21, 5, 39, 725, 999, "21:05:39.725999", "\159\032\177\157\059\138\242\064" ; 6, 45, 2, 883, 216, "06:45:02.883216", "\212\102\156\134\184\187\215\064" ; 1, 15, 59, 714, 389, "01:15:59.714389", "\159\143\050\226\182\207\177\064" ; 13, 31, 54, 512, 665, "13:31:54.512665", "\026\110\192\103\080\201\231\064" ; 3, 44, 13, 197, 547, "03:44:13.197547", "\054\088\056\073\153\070\202\064" ; 16, 20, 27, 507, 65, "16:20:27.507065", "\254\096\224\057\112\185\236\064" ; 6, 48, 3, 259, 916, "06:48:03.259916", "\237\183\118\162\208\232\215\064" ; 16, 49, 26, 728, 147, "16:49:26.728147", "\246\239\250\076\215\146\237\064" ; 4, 15, 29, 802, 53, "04:15:29.802053", "\084\054\172\169\230\240\205\064" ; 14, 37, 11, 974, 359, "14:37:11.974359", "\242\236\242\045\255\178\233\064" ; 14, 4, 58, 206, 159, "14:04:58.206159", "\089\194\218\152\070\193\232\064" ; 9, 50, 7, 638, 198, "09:50:07.638198", "\076\054\030\108\244\073\225\064" ; 10, 37, 53, 335, 169, "10:37:53.335169", "\180\086\180\185\042\176\226\064" ; 10, 43, 51, 744, 232, "10:43:51.744232", "\148\160\191\208\247\220\226\064" ; 8, 26, 3, 203, 599, "08:26:03.203599", "\160\025\196\007\205\166\221\064" ; 16, 4, 27, 28, 854, "16:04:27.028854", "\075\057\095\236\096\065\236\064" ; 16, 21, 24, 409, 589, "16:21:24.409589", "\250\099\090\027\141\192\236\064" ; 17, 2, 57, 58, 508, "17:02:57.058508", "\081\043\076\223\033\248\237\064" ; 13, 9, 9, 829, 706, "13:09:09.829706", "\233\152\243\140\186\030\231\064" ; 2, 39, 22, 426, 92, "02:39:22.426092", "\139\194\046\138\054\173\194\064" ; 10, 45, 6, 995, 67, "10:45:06.995067", "\203\191\150\215\095\230\226\064" ; 11, 45, 12, 391, 863, "11:45:12.391863", "\049\070\036\138\012\169\228\064" ; 3, 54, 1, 108, 529, "03:54:01.108529", "\214\060\071\228\141\108\203\064" ; 16, 28, 16, 554, 5, "16:28:16.554005", "\154\177\104\186\017\244\236\064" ; 11, 27, 43, 594, 962, "11:27:43.594962", "\139\191\237\009\243\037\228\064" ; 11, 26, 30, 297, 26, "11:26:30.297026", "\130\171\060\129\201\028\228\064" ; 16, 32, 32, 803, 820, "16:32:32.803820", "\124\184\228\184\025\020\237\064" ; 0, 10, 23, 158, 219, "00:10:23.158219", "\217\180\082\008\068\121\131\064" ; 17, 43, 25, 760, 634, "17:43:25.760634", "\072\029\029\087\184\039\239\064" ; 4, 34, 26, 253, 262, "04:34:26.253262", "\213\209\113\053\144\020\208\064" ; 9, 30, 40, 411, 802, "09:30:40.411802", "\078\099\123\045\013\184\224\064" ; 13, 2, 39, 673, 232, "13:02:39.673232", "\212\213\029\139\245\237\230\064" ; 22, 8, 21, 242, 87, "22:08:21.242087", "\060\158\150\223\083\117\243\064" ; 21, 21, 46, 934, 600, "21:21:46.934600", "\045\033\031\244\174\198\242\064" ; 22, 49, 17, 897, 957, "22:49:17.897957", "\195\040\008\094\222\014\244\064" ; 11, 42, 45, 124, 15, "11:42:45.124015", "\039\078\238\247\163\150\228\064" ; 5, 53, 22, 742, 552, "05:53:22.742552", "\229\210\248\133\175\180\212\064" ; 21, 8, 17, 213, 779, "21:08:17.213779", "\089\135\163\107\019\148\242\064" ; 9, 52, 37, 114, 537, "09:52:37.114537", "\166\127\073\170\163\092\225\064" ; 3, 39, 6, 350, 498, "03:39:06.350498", "\168\083\030\221\044\173\201\064" ; 12, 51, 1, 858, 804, "12:51:01.858804", "\182\134\082\123\187\150\230\064" ; 2, 31, 46, 93, 343, "02:31:46.093343", "\040\214\169\242\011\201\193\064" ; 20, 56, 41, 693, 738, "20:56:41.693738", "\096\004\141\025\155\104\242\064" ; 23, 21, 52, 94, 368, "23:21:52.094368", "\028\005\136\130\001\137\244\064" ; 11, 5, 6, 914, 293, "11:05:06.914293", "\190\100\227\065\093\124\227\064" ; 9, 48, 20, 185, 135, "09:48:20.185135", "\075\060\160\236\133\060\225\064" ; 21, 46, 59, 452, 421, "21:46:59.452421", "\113\205\029\061\055\037\243\064" ; 14, 59, 27, 541, 936, "14:59:27.541936", "\144\042\138\087\241\089\234\064" ; 10, 52, 21, 157, 458, "10:52:21.157458", "\016\092\229\009\165\028\227\064" ; 14, 58, 30, 941, 598, "14:58:30.941598", "\255\032\146\033\222\082\234\064" ; 19, 38, 23, 297, 641, "19:38:23.297641", "\144\053\035\195\244\066\241\064" ; 23, 59, 47, 456, 383, "23:59:47.456383", "\184\066\088\077\055\023\245\064" ; 13, 59, 35, 279, 733, "13:59:35.279733", "\212\158\146\243\232\152\232\064" ; 17, 14, 8, 378, 894, "17:14:08.378894", "\084\079\230\031\012\076\238\064" ; 15, 32, 25, 237, 667, "15:32:25.237667", "\011\211\247\154\039\081\235\064" ; 0, 7, 18, 374, 582, "00:07:18.374582", "\186\250\177\073\254\101\123\064" ; 9, 26, 32, 591, 377, "09:26:32.591377", "\083\117\143\236\018\153\224\064" ; 23, 23, 21, 669, 253, "23:23:21.669253", "\060\162\066\181\154\142\244\064" ; 12, 57, 21, 637, 593, "12:57:21.637593", "\101\111\041\103\052\198\230\064" ; 17, 56, 29, 418, 946, "17:56:29.418946", "\025\113\001\104\173\137\239\064" ; 7, 12, 58, 180, 503, "07:12:58.180503", "\117\116\092\141\139\094\217\064" ; 0, 32, 20, 346, 888, "00:32:20.346888", "\128\157\155\054\099\081\158\064" ; 14, 58, 35, 541, 92, "14:58:35.541092", "\132\043\160\080\113\083\234\064" ; 3, 16, 5, 701, 280, "03:16:05.701280", "\171\004\139\195\217\250\198\064" ; 12, 49, 28, 869, 691, "12:49:28.869691", "\084\056\130\212\027\139\230\064" ; 16, 27, 34, 272, 379, "16:27:34.272379", "\035\042\084\183\200\238\236\064" ; 11, 6, 11, 137, 954, "11:06:11.137954", "\204\129\030\106\100\132\227\064" ; 5, 27, 10, 612, 643, "05:27:10.612643", "\072\252\138\053\167\043\211\064" ; 8, 1, 4, 442, 874, "08:01:04.442874", "\144\048\012\088\028\048\220\064" ; 17, 18, 16, 838, 301, "17:18:16.838301", "\103\158\092\211\026\107\238\064" ; 22, 44, 25, 239, 914, "22:44:25.239914", "\254\015\176\214\147\252\243\064" ; 15, 11, 44, 638, 139, "15:11:44.638139", "\234\122\162\107\020\182\234\064" ; 11, 22, 31, 519, 935, "11:22:31.519935", "\161\185\078\163\240\254\227\064" ; 22, 37, 51, 57, 741, "22:37:51.057741", "\170\211\129\236\240\227\243\064" ; 6, 50, 20, 797, 787, "06:50:20.797787", "\139\052\241\014\051\011\216\064" ; 12, 34, 19, 439, 250, "12:34:19.439250", "\024\004\086\014\110\025\230\064" ; 0, 3, 29, 243, 367, "00:03:29.243367", "\159\061\151\169\201\039\106\064" ; 5, 8, 1, 171, 492, "05:08:01.171492", "\225\148\185\249\074\012\210\064" ; 7, 46, 48, 977, 746, "07:46:48.977746", "\115\245\099\147\062\090\219\064" ; 3, 56, 54, 198, 343, "03:56:54.198343", "\050\173\077\099\025\195\203\064" ; 1, 23, 56, 540, 309, "01:23:56.540309", "\188\204\176\081\138\172\179\064" ; 19, 52, 55, 140, 343, "19:52:55.140343", "\052\077\216\062\114\121\241\064" ; 5, 23, 25, 712, 358, "05:23:25.712358", "\067\002\070\151\109\243\210\064" ; 17, 42, 26, 186, 813, "17:42:26.186813", "\175\065\095\250\069\032\239\064" ; 21, 7, 47, 15, 565, "21:07:47.015565", "\223\021\193\063\048\146\242\064" ; 13, 39, 26, 33, 762, "13:39:26.033762", "\188\011\148\020\193\001\232\064" ; 2, 30, 21, 480, 931, "02:30:21.480931", "\081\162\037\143\189\158\193\064" ; 9, 26, 19, 30, 958, "09:26:19.030958", "\177\161\155\253\096\151\224\064" ; 18, 12, 53, 885, 704, "18:12:53.885704", "\031\245\215\043\094\002\240\064" ; 22, 49, 25, 33, 96, "22:49:25.033096", "\218\171\143\135\080\015\244\064" ; 11, 55, 14, 458, 765, "11:55:14.458765", "\241\239\051\174\078\244\228\064" ; 5, 35, 55, 256, 870, "05:35:55.256870", "\085\222\142\112\208\174\211\064" ; 21, 33, 24, 0, 948, "21:33:24.000948", "\208\012\226\003\064\242\242\064" ; 8, 11, 58, 660, 793, "08:11:58.660793", "\027\185\110\074\170\211\220\064" ; 22, 3, 9, 732, 300, "22:03:09.732300", "\110\052\128\183\219\097\243\064" ; 5, 29, 37, 534, 210, "05:29:37.534210", "\204\035\127\048\098\080\211\064" ; 4, 18, 43, 295, 126, "04:18:43.295126", "\026\083\176\198\165\081\206\064" ; 14, 11, 50, 122, 763, "14:11:50.122763", "\197\171\172\237\195\244\232\064" ; 12, 35, 30, 785, 224, "12:35:30.785224", "\002\021\142\032\089\034\230\064" ; 0, 35, 43, 147, 858, "00:35:43.147858", "\231\052\011\180\075\190\160\064" ; 1, 41, 17, 899, 872, "01:41:17.899872", "\150\234\002\094\230\189\183\064" ; 23, 4, 44, 199, 192, "23:04:44.199192", "\090\243\227\047\195\072\244\064" ; 5, 32, 4, 920, 875, "05:32:04.920875", "\045\178\157\239\058\117\211\064" ; 10, 7, 37, 262, 566, "10:07:37.262566", "\226\207\240\102\040\205\225\064" ; 17, 59, 42, 856, 785, "17:59:42.856785", "\086\096\200\106\219\161\239\064" ; 8, 41, 42, 694, 309, "08:41:42.694309", "\020\004\143\111\172\145\222\064" ; 17, 4, 6, 15, 115, "17:04:06.015115", "\214\115\210\123\192\000\238\064" ; 1, 42, 13, 880, 186, "01:42:13.880186", "\102\164\222\083\225\245\183\064" ; 22, 22, 15, 665, 696, "22:22:15.665696", "\081\217\176\166\122\169\243\064" ; 4, 2, 50, 626, 603, "04:02:50.626603", "\074\240\134\052\080\117\204\064" ; 10, 51, 12, 930, 664, "10:51:12.930664", "\114\222\255\199\029\020\227\064" ; 1, 8, 29, 166, 713, "01:08:29.166713", "\210\002\180\173\042\013\176\064" ; 10, 15, 9, 326, 930, "10:15:09.326930", "\067\231\053\118\170\005\226\064" ; 17, 27, 18, 157, 64, "17:27:18.157064", "\236\020\171\006\197\174\238\064" ; 13, 2, 24, 561, 739, "13:02:24.561739", "\061\017\196\249\017\236\230\064" ; 18, 43, 11, 839, 259, "18:43:11.839259", "\094\216\154\109\253\115\240\064" ; 2, 48, 15, 648, 993, "02:48:15.648993", "\042\223\051\018\211\183\195\064" ; 21, 23, 52, 403, 556, "21:23:52.403556", "\226\034\247\116\134\206\242\064" ; 4, 3, 2, 413, 396, "04:03:02.413396", "\038\254\040\234\052\123\204\064" ; 21, 31, 32, 45, 472, "21:31:32.045472", "\014\217\064\186\064\235\242\064" ; 23, 24, 14, 426, 351, "23:24:14.426351", "\026\109\085\210\230\145\244\064" ; 14, 27, 18, 459, 785, "14:27:18.459785", "\070\008\143\182\206\104\233\064" ; 22, 32, 8, 99, 271, "22:32:08.099271", "\039\048\157\150\129\206\243\064" ; 18, 9, 4, 138, 932, "18:09:04.138932", "\140\133\033\114\004\232\239\064" ; 12, 5, 24, 996, 292, "12:05:24.996292", "\168\194\159\225\159\064\229\064" ; 19, 19, 31, 950, 647, "19:19:31.950647", "\240\160\217\053\063\252\240\064" ; 12, 56, 53, 688, 62, "12:56:53.688062", "\116\153\154\004\182\194\230\064" ; 5, 14, 50, 621, 779, "05:14:50.621779", "\150\037\058\203\167\114\210\064" ; 23, 39, 56, 944, 735, "23:39:56.944735", "\134\114\162\029\207\204\244\064" ; 22, 24, 48, 253, 495, "22:24:48.253495", "\235\197\080\014\004\179\243\064" ; 8, 46, 35, 445, 128, "08:46:35.445128", "\162\038\250\124\220\218\222\064" ; 7, 44, 27, 431, 20, "07:44:27.431020", "\251\232\212\149\219\054\219\064" ; 10, 4, 43, 572, 113, "10:04:43.572113", "\020\236\191\078\114\183\225\064" ; 1, 33, 45, 292, 75, "01:33:45.292075", "\251\092\109\197\074\249\181\064" ; 14, 5, 52, 961, 456, "14:05:52.961456", "\146\095\063\196\030\200\232\064" ; 15, 56, 19, 372, 889, "15:56:19.372889", "\130\233\180\238\107\004\236\064" ; 12, 25, 11, 702, 407, "12:25:11.702407", "\175\062\030\122\246\212\229\064" ; 21, 19, 47, 421, 168, "21:19:47.421168", "\034\168\026\189\054\191\242\064" ; 6, 43, 50, 998, 71, "06:43:50.998071", "\005\048\101\224\191\169\215\064" ; 20, 44, 0, 467, 738, "20:44:00.467738", "\082\215\218\123\007\057\242\064" ; 16, 20, 44, 681, 243, "16:20:44.681243", "\180\030\190\204\149\187\236\064" ; 14, 26, 37, 349, 853, "14:26:37.349853", "\045\235\254\049\171\099\233\064" ; 20, 14, 56, 666, 675, "20:14:56.666675", "\161\103\179\170\010\204\241\064" ; 5, 7, 51, 853, 414, "05:07:51.853414", "\252\192\085\158\246\009\210\064" ; 11, 9, 44, 669, 19, "11:09:44.669019", "\173\136\154\104\021\159\227\064" ; 10, 14, 8, 980, 465, "10:14:08.980465", "\188\034\248\095\031\254\225\064" ; 8, 32, 27, 831, 380, "08:32:27.831380", "\163\117\084\053\245\006\222\064" ; 13, 58, 56, 166, 145, "13:58:56.166145", "\172\081\015\081\005\148\232\064" ; 12, 50, 8, 906, 524, "12:50:08.906524", "\162\158\062\002\029\144\230\064" ; 2, 42, 29, 855, 547, "02:42:29.855547", "\152\104\144\130\237\010\195\064" ; 9, 30, 14, 962, 398, "09:30:14.962398", "\247\227\246\203\222\180\224\064" ; 7, 51, 18, 995, 246, "07:51:18.995246", "\094\071\028\178\191\157\219\064" ; 15, 47, 4, 67, 210, "15:47:04.067210", "\255\149\149\038\002\191\235\064" ; 15, 28, 53, 326, 269, "15:28:53.326269", "\150\175\203\112\170\054\235\064" ; 18, 0, 11, 217, 836, "18:00:11.217836", "\252\051\131\248\102\165\239\064" ; 9, 48, 0, 563, 743, "09:48:00.563743", "\139\194\046\010\018\058\225\064" ; 21, 27, 19, 865, 65, "21:27:19.865065", "\191\101\078\215\125\219\242\064" ; 0, 30, 58, 15, 15, "00:30:58.015015", "\205\151\023\096\015\008\157\064" ; 2, 46, 9, 412, 201, "02:46:09.412201", "\049\155\000\195\180\120\195\064" ; 11, 5, 50, 943, 69, "11:05:50.943069", "\028\010\159\045\222\129\227\064" ; 11, 26, 4, 787, 159, "11:26:04.787159", "\056\018\104\048\153\025\228\064" ; 14, 35, 11, 668, 597, "14:35:11.668597", "\038\137\037\101\245\163\233\064" ; 11, 20, 25, 735, 594, "11:20:25.735594", "\164\109\252\137\055\239\227\064" ; 2, 17, 25, 6, 40, "02:17:25.006040", "\060\049\235\197\128\026\192\064" ; 4, 49, 39, 631, 77, "04:49:39.631077", "\017\201\144\099\232\248\208\064" ; 10, 44, 11, 970, 574, "10:44:11.970574", "\139\052\241\014\127\223\226\064" ; 16, 4, 19, 373, 988, "16:04:19.373988", "\163\174\181\247\107\064\236\064" ; 20, 15, 47, 663, 643, "20:15:47.663643", "\084\031\072\158\058\207\241\064" ; 20, 38, 6, 925, 261, "20:38:06.925261", "\116\122\222\205\238\034\242\064" ; 8, 36, 0, 595, 790, "08:36:00.595790", "\082\097\108\033\038\060\222\064" ; 18, 8, 53, 149, 520, "18:08:53.149520", "\195\042\222\200\164\230\239\064" ; 0, 33, 2, 774, 544, "00:33:02.774544", "\064\245\015\034\025\251\158\064" ; 1, 42, 45, 8, 929, "01:42:45.008929", "\252\194\043\073\002\021\184\064" ; 15, 35, 2, 599, 392, "15:35:02.599392", "\176\033\056\046\211\100\235\064" ; 3, 29, 50, 723, 138, "03:29:50.723138", "\063\054\201\143\092\151\200\064" ; 17, 27, 59, 615, 637, "17:27:59.615637", "\166\093\076\179\243\179\238\064" ; 22, 27, 39, 255, 879, "22:27:39.255879", "\012\148\020\024\180\189\243\064" ; 9, 29, 37, 983, 943, "09:29:37.983943", "\196\007\118\124\063\176\224\064" ; 7, 40, 56, 268, 649, "07:40:56.268649", "\071\147\139\049\017\002\219\064" ; 17, 46, 1, 88, 944, "17:46:01.088944", "\102\022\161\216\034\059\239\064" ; 2, 14, 58, 165, 244, "02:14:58.165244", "\220\071\110\077\042\162\191\064" ; 5, 28, 11, 962, 988, "05:28:11.962988", "\156\107\152\161\253\058\211\064" ; 15, 46, 10, 921, 15, "15:46:10.921015", "\004\115\244\120\093\184\235\064" ; 19, 22, 44, 167, 205, "19:22:44.167205", "\108\038\223\172\066\008\241\064" ; 1, 41, 24, 924, 607, "01:41:24.924607", "\167\090\011\179\236\196\183\064" ; 11, 54, 28, 42, 158, "11:54:28.042158", "\233\187\091\089\129\238\228\064" ; 14, 54, 33, 444, 941, "14:54:33.444941", "\117\232\244\060\046\053\234\064" ; 0, 50, 6, 970, 619, "00:50:06.970619", "\192\059\249\244\240\125\167\064" ; 8, 50, 56, 139, 929, "08:50:56.139929", "\177\195\152\244\008\028\223\064" ; 12, 11, 57, 306, 316, "12:11:57.306316", "\071\054\087\205\169\113\229\064" ; 14, 3, 55, 69, 740, "14:03:55.069740", "\104\097\079\059\098\185\232\064" ; 1, 37, 12, 686, 696, "01:37:12.686696", "\075\030\079\203\175\200\182\064" ; 0, 14, 27, 954, 771, "00:14:27.954771", "\090\097\250\094\163\031\139\064" ; 5, 55, 32, 322, 851, "05:55:32.322851", "\159\061\151\169\020\213\212\064" ; 6, 48, 38, 184, 610, "06:48:38.184610", "\033\118\166\208\139\241\215\064" ; 7, 59, 17, 728, 574, "07:59:17.728574", "\174\215\244\160\110\021\220\064" ; 3, 26, 9, 427, 94, "03:26:09.427094", "\041\037\004\171\182\040\200\064" ; 23, 39, 26, 260, 173, "23:39:26.260173", "\228\041\171\041\228\202\244\064" ; 8, 7, 43, 165, 735, "08:07:43.165735", "\052\249\102\155\202\147\220\064" ; 2, 41, 54, 490, 148, "02:41:54.490148", "\025\111\043\189\062\249\194\064" ; 5, 58, 51, 86, 210, "05:58:51.086210", "\165\242\118\132\197\006\213\064" ; 17, 32, 48, 749, 996, "17:32:48.749996", "\133\156\247\255\023\216\238\064" ; 13, 8, 25, 18, 98, "13:08:25.018098", "\195\065\066\148\032\025\231\064" ; 16, 35, 53, 719, 921, "16:35:53.719921", "\214\195\151\009\055\045\237\064" ; 11, 36, 14, 988, 587, "11:36:14.988587", "\072\052\129\162\223\101\228\064" ; 16, 27, 52, 304, 365, "16:27:52.304365", "\033\171\091\189\009\241\236\064" ; 21, 30, 13, 374, 163, "21:30:13.374163", "\134\087\146\252\085\230\242\064" ; 7, 26, 58, 372, 288, "07:26:58.372288", "\044\012\145\211\151\048\218\064" ; 19, 7, 31, 277, 592, "19:07:31.277592", "\026\079\004\113\052\207\240\064" ; 7, 40, 39, 953, 756, "07:40:39.953756", "\024\155\086\010\253\253\218\064" ; 7, 2, 17, 517, 437, "07:02:17.517437", "\047\020\176\029\097\190\216\064" ; 18, 51, 38, 547, 755, "18:51:38.547755", "\052\191\154\195\168\147\240\064" ; 18, 32, 48, 626, 109, "18:32:48.626109", "\236\222\138\004\010\077\240\064" ; 14, 12, 16, 421, 763, "14:12:16.421763", "\117\030\021\127\013\248\232\064" ; 4, 8, 6, 255, 808, "04:08:06.255808", "\007\009\081\190\032\019\205\064" ; 3, 22, 13, 512, 592, "03:22:13.512592", "\025\090\157\156\193\178\199\064" ; 11, 1, 36, 619, 363, "11:01:36.619363", "\171\090\210\209\019\098\227\064" ; 1, 44, 27, 301, 163, "01:44:27.301163", "\196\179\004\025\077\123\184\064" ; 6, 56, 39, 216, 675, "06:56:39.216675", "\183\209\000\222\205\105\216\064" ; 10, 27, 45, 98, 510, "10:27:45.098510", "\138\113\254\038\035\100\226\064" ; 12, 50, 51, 698, 183, "12:50:51.698183", "\243\223\131\087\118\149\230\064" ; 20, 24, 26, 941, 302, "20:24:26.941302", "\155\175\146\015\175\239\241\064" ; 7, 13, 5, 609, 927, "07:13:05.609927", "\125\065\011\009\103\096\217\064" ; 9, 28, 36, 783, 693, "09:28:36.783693", "\164\087\003\020\153\168\224\064" ; 8, 9, 45, 817, 911, "08:09:45.817911", "\002\097\167\088\116\178\220\064" ; 20, 20, 42, 636, 697, "20:20:42.636697", "\135\049\233\047\170\225\241\064" ; 17, 27, 47, 555, 478, "17:27:47.555478", "\117\204\121\198\113\178\238\064" ; 17, 8, 40, 353, 271, "17:08:40.353271", "\244\251\254\077\011\035\238\064" ; 5, 47, 46, 635, 434, "05:47:46.635434", "\049\094\243\170\168\096\212\064" ; 3, 11, 48, 329, 494, "03:11:48.329494", "\029\001\220\044\042\122\198\064" ; 9, 54, 10, 642, 259, "09:54:10.642259", "\018\191\098\141\084\104\225\064" ; 0, 28, 9, 995, 543, "00:28:09.995543", "\012\203\159\111\251\103\154\064" ; 4, 47, 59, 395, 333, "04:47:59.395333", "\130\200\034\077\217\223\208\064" ; 5, 44, 46, 505, 176, "05:44:46.505176", "\175\183\205\084\160\051\212\064" ; 9, 30, 23, 261, 84, "09:30:23.261084", "\048\213\204\090\232\181\224\064" ; 20, 34, 3, 264, 480, "20:34:03.264480", "\103\097\079\059\180\019\242\064" ; 2, 59, 28, 336, 512, "02:59:28.336512", "\091\065\211\018\043\008\197\064" ; 2, 45, 8, 687, 667, "02:45:08.687667", "\197\229\120\005\088\090\195\064" ; 11, 52, 49, 154, 841, "11:52:49.154841", "\227\028\117\244\036\226\228\064" ; 16, 28, 51, 76, 481, "16:28:51.076481", "\057\072\136\114\098\248\236\064" ; 9, 59, 35, 781, 131, "09:59:35.781131", "\093\112\006\255\248\144\225\064" ; 6, 53, 38, 721, 781, "06:53:38.721781", "\120\239\168\049\174\060\216\064" ; 8, 58, 55, 308, 846, "08:58:55.308846", "\096\003\034\196\211\147\223\064" ; 5, 15, 0, 193, 558, "05:15:00.193558", "\248\023\065\099\012\117\210\064" ; 20, 59, 20, 695, 675, "20:59:20.695675", "\219\027\124\033\139\114\242\064" ; 23, 48, 37, 78, 966, "23:48:37.078966", "\056\218\113\067\081\237\244\064" ; 1, 3, 7, 688, 205, "01:03:07.688205", "\227\223\103\092\096\151\173\064" ; 11, 54, 47, 958, 306, "11:54:47.958306", "\050\088\113\170\254\240\228\064" ; 1, 23, 0, 972, 409, "01:23:00.972409", "\086\213\203\239\248\116\179\064" ; 20, 32, 39, 867, 606, "20:32:39.867606", "\061\212\182\225\125\014\242\064" ; 7, 3, 34, 467, 9, "07:03:34.467009", "\124\183\121\227\157\209\216\064" ; 4, 50, 18, 702, 43, "04:50:18.702043", "\089\195\069\238\172\002\209\064" ; 17, 55, 12, 531, 637, "17:55:12.531637", "\011\153\043\003\017\128\239\064" ; 21, 14, 37, 539, 883, "21:14:37.539883", "\075\091\092\163\216\171\242\064" ; 1, 59, 53, 321, 485, "01:59:53.321485", "\039\073\215\076\082\025\188\064" ; 16, 19, 43, 986, 226, "16:19:43.986226", "\014\212\041\143\255\179\236\064" ; 2, 36, 59, 93, 640, "02:36:59.093640", "\205\064\101\252\139\101\194\064" ; 21, 4, 42, 749, 427, "21:04:42.749427", "\124\042\167\253\171\134\242\064" ; 6, 58, 1, 135, 376, "06:58:01.135376", "\042\025\000\170\072\126\216\064" ; 8, 46, 15, 38, 754, "08:46:15.038754", "\166\014\242\122\194\213\222\064" ; 16, 44, 44, 285, 836, "16:44:44.285836", "\001\138\145\037\137\111\237\064" ; 3, 35, 20, 829, 307, "03:35:20.829307", "\172\085\187\038\106\060\201\064" ; 10, 25, 6, 189, 825, "10:25:06.189825", "\223\224\011\019\070\080\226\064" ; 13, 55, 4, 366, 790, "13:55:04.366790", "\208\097\190\188\011\119\232\064" ; 9, 41, 3, 972, 628, "09:41:03.972628", "\102\193\196\031\255\005\225\064" ; 19, 16, 30, 951, 315, "19:16:30.951315", "\211\019\150\056\239\240\240\064" ; 15, 47, 56, 431, 433, "15:47:56.431433", "\045\148\076\206\141\197\235\064" ; 20, 28, 7, 207, 748, "20:28:07.207748", "\029\145\239\082\115\253\241\064" ; 9, 13, 5, 275, 923, "09:13:05.275923", "\167\120\092\212\040\052\224\064" ; 1, 49, 34, 70, 158, "01:49:34.070158", "\141\235\223\245\017\174\185\064" ; 13, 4, 7, 294, 321, "13:04:07.294321", "\177\223\019\107\233\248\230\064" ; 4, 22, 23, 601, 285, "04:22:23.601285", "\074\041\232\246\204\191\206\064" ; 11, 27, 17, 127, 779, "11:27:17.127779", "\068\252\195\022\164\034\228\064" ; 9, 20, 18, 252, 877, "09:20:18.252877", "\157\129\145\023\072\106\224\064" ; 7, 6, 17, 930, 754, "07:06:17.930754", "\168\057\121\145\123\250\216\064" ; 16, 17, 26, 251, 244, "16:17:26.251244", "\106\219\048\010\200\162\236\064" ; 20, 35, 45, 726, 724, "20:35:45.726724", "\083\088\169\160\027\026\242\064" ; 17, 43, 43, 369, 798, "17:43:43.369798", "\132\157\098\213\235\041\239\064" ; 9, 1, 3, 13, 796, "09:01:03.013796", "\052\158\008\226\192\179\223\064" ; 8, 57, 37, 926, 415, "08:57:37.926415", "\225\035\098\074\123\128\223\064" ; 2, 18, 40, 239, 745, "02:18:40.239745", "\048\211\246\175\030\064\192\064" ; 6, 32, 37, 199, 831, "06:32:37.199831", "\111\246\007\202\076\001\215\064" ; 13, 27, 56, 131, 13, "13:27:56.131013", "\203\044\066\049\132\171\231\064" ; 6, 44, 51, 216, 646, "06:44:51.216646", "\052\047\135\221\205\184\215\064" ; 17, 0, 31, 36, 927, "17:00:31.036927", "\043\136\129\046\225\229\237\064" ; 19, 38, 57, 486, 404, "19:38:57.486404", "\139\143\079\200\023\069\241\064" ; 19, 47, 32, 881, 450, "19:47:32.881450", "\177\080\107\026\078\101\241\064" ; 22, 52, 50, 444, 639, "22:52:50.444639", "\185\200\061\029\039\028\244\064" ; 2, 45, 50, 431, 989, "02:45:50.431989", "\158\097\106\075\055\111\195\064" ; 14, 35, 5, 951, 564, "14:35:05.951564", "\130\088\054\115\062\163\233\064" ; 15, 3, 24, 644, 527, "15:03:24.644527", "\076\022\247\159\148\119\234\064" ; 9, 24, 28, 722, 680, "09:24:28.722680", "\175\206\049\032\151\137\224\064" ; 0, 43, 13, 118, 380, "00:43:13.118380", "\000\169\077\156\060\066\164\064" ; 17, 55, 12, 509, 639, "17:55:12.509639", "\184\114\246\078\016\128\239\064" ; 12, 58, 56, 97, 550, "12:58:56.097550", "\119\045\033\031\003\210\230\064" ; 6, 5, 47, 67, 650, "06:05:47.067650", "\101\170\096\084\196\110\213\064" ; 4, 12, 49, 578, 319, "04:12:49.578319", "\212\099\091\006\202\160\205\064" ; 8, 15, 27, 597, 197, "08:15:27.597197", "\018\196\121\056\230\007\221\064" ; 8, 34, 39, 932, 78, "08:34:39.932078", "\213\123\042\167\251\039\222\064" ; 4, 13, 54, 627, 96, "04:13:54.627096", "\186\133\174\068\080\193\205\064" ; 22, 1, 38, 888, 494, "22:01:38.888494", "\012\124\069\055\046\092\243\064" ; 14, 36, 54, 328, 909, "14:36:54.328909", "\204\042\108\134\202\176\233\064" ; 0, 34, 18, 5, 739, "00:34:18.005739", "\160\226\056\240\002\020\160\064" ; 1, 29, 30, 508, 163, "01:29:30.508163", "\009\106\248\022\130\250\180\064" ; 21, 17, 59, 597, 984, "21:17:59.597984", "\184\171\087\145\121\184\242\064" ; 3, 59, 16, 616, 551, "03:59:16.616551", "\168\166\036\235\078\010\204\064" ; 16, 28, 8, 839, 523, "16:28:08.839523", "\168\086\095\221\026\243\236\064" ; 18, 15, 11, 262, 444, "18:15:11.262444", "\209\122\248\050\244\010\240\064" ; 7, 59, 30, 485, 149, "07:59:30.485149", "\044\100\174\012\159\024\220\064" ; 4, 44, 35, 321, 929, "04:44:35.321929", "\169\023\124\154\212\172\208\064" ; 3, 52, 28, 794, 427, "03:52:28.794427", "\008\176\200\175\101\062\203\064" ; 4, 58, 15, 919, 229, "04:58:15.919229", "\035\223\165\212\250\121\209\064" ; 13, 46, 24, 790, 621, "13:46:24.790621", "\081\105\196\076\025\054\232\064" ; 3, 38, 42, 542, 85, "03:38:42.542085", "\083\145\010\099\069\161\201\064" ; 14, 34, 24, 81, 354, "14:34:24.081354", "\045\180\115\154\002\158\233\064" ; 11, 52, 57, 888, 501, "11:52:57.888501", "\047\166\153\110\060\227\228\064" ; 8, 48, 39, 591, 687, "08:48:39.591687", "\158\038\051\222\229\249\222\064" ; 6, 25, 24, 726, 705, "06:25:24.726705", "\053\176\085\130\046\149\214\064" ; 11, 35, 47, 871, 319, "11:35:47.871319", "\044\098\216\225\123\098\228\064" ; 8, 11, 57, 624, 250, "08:11:57.624250", "\162\069\182\243\103\211\220\064" ; 5, 50, 28, 209, 32, "05:50:28.209032", "\244\192\199\096\013\137\212\064" ; 8, 38, 31, 358, 488, "08:38:31.358488", "\001\167\119\241\214\097\222\064" ; 14, 45, 48, 510, 625, "14:45:48.510625", "\113\061\010\087\144\243\233\064" ; 10, 34, 43, 192, 531, "10:34:43.192531", "\143\197\054\041\102\152\226\064" ; 1, 23, 24, 952, 524, "01:23:24.952524", "\168\228\156\216\243\140\179\064" ; 12, 57, 12, 818, 62, "12:57:12.818062", "\003\092\144\045\026\197\230\064" ; 5, 23, 15, 598, 873, "05:23:15.598873", "\094\107\239\083\230\240\210\064" ; 18, 27, 5, 992, 800, "18:27:05.992800", "\183\064\130\226\159\055\240\064" ; 1, 11, 39, 656, 337, "01:11:39.656337", "\040\158\179\005\168\203\176\064" ; 14, 15, 19, 617, 875, "14:15:19.617875", "\192\202\161\197\243\014\233\064" ; 7, 48, 39, 632, 405, "07:48:39.632405", "\053\210\082\121\232\117\219\064" ; 6, 57, 31, 221, 585, "06:57:31.221585", "\019\218\114\046\206\118\216\064" ; 3, 7, 59, 254, 190, "03:07:59.254190", "\125\068\076\137\160\007\198\064" ; 18, 8, 35, 57, 4, "18:08:35.057004", "\120\013\250\210\097\228\239\064" ; 2, 7, 58, 721, 896, "02:07:58.721896", "\028\031\045\206\184\254\189\064" ; 13, 23, 13, 475, 481, "13:23:13.475481", "\028\238\035\055\047\136\231\064" ; 19, 39, 48, 812, 459, "19:39:48.812459", "\038\002\213\255\076\072\241\064" ; 13, 7, 40, 664, 104, "13:07:40.664104", "\036\008\087\064\149\019\231\064" ; 20, 27, 2, 704, 755, "20:27:02.704755", "\203\045\173\070\107\249\241\064" ; 0, 30, 49, 906, 158, "00:30:49.906158", "\009\252\225\231\159\231\156\064" ; 21, 16, 5, 274, 657, "21:16:05.274657", "\010\189\254\100\084\177\242\064" ; 16, 4, 44, 529, 950, "16:04:44.529950", "\209\179\089\245\144\067\236\064" ; 12, 43, 19, 613, 588, "12:43:19.613588", "\039\077\131\162\243\092\230\064" ; 19, 2, 54, 410, 942, "19:02:54.410942", "\041\235\055\147\230\189\240\064" ; 18, 10, 12, 333, 649, "18:10:12.333649", "\235\170\064\173\138\240\239\064" ; 20, 15, 52, 441, 67, "20:15:52.441067", "\070\069\156\014\135\207\241\064" ; 5, 51, 33, 201, 943, "05:51:33.201943", "\042\085\162\236\076\153\212\064" ; 15, 43, 26, 540, 689, "15:43:26.540689", "\138\004\083\077\209\163\235\064" ; 15, 19, 33, 965, 828, "15:19:33.965828", "\049\031\016\232\190\240\234\064" ; 17, 21, 44, 521, 925, "17:21:44.521925", "\191\014\156\179\016\133\238\064" ; 4, 8, 36, 463, 372, "04:08:36.463372", "\241\016\198\079\059\034\205\064" ; 8, 27, 19, 928, 343, "08:27:19.928343", "\030\194\248\105\251\185\221\064" ; 13, 33, 44, 503, 903, "13:33:44.503903", "\043\047\249\031\016\215\231\064" ; 14, 8, 40, 998, 367, "14:08:40.998367", "\205\089\159\242\031\221\232\064" ; 13, 29, 27, 278, 619, "13:29:27.278619", "\161\100\114\234\232\182\231\064" ; 14, 21, 18, 325, 80, "14:21:18.325080", "\018\044\014\103\202\059\233\064" ; 21, 41, 57, 348, 920, "21:41:57.348920", "\079\035\045\149\085\018\243\064" ; 2, 6, 15, 800, 593, "02:06:15.800593", "\104\176\169\243\204\151\189\064" ; 20, 45, 43, 560, 779, "20:45:43.560779", "\148\102\243\248\120\063\242\064" ; 21, 24, 3, 106, 99, "21:24:03.106099", "\114\221\148\178\049\207\242\064" ; 9, 7, 37, 296, 827, "09:07:37.296827", "\051\086\155\127\041\011\224\064" ; 20, 6, 47, 850, 437, "20:06:47.850437", "\229\211\099\155\125\173\241\064" ; 11, 45, 7, 115, 600, "11:45:07.115600", "\109\197\254\178\099\168\228\064" ; 13, 14, 25, 985, 627, "13:14:25.985627", "\098\162\065\138\063\070\231\064" ; 16, 23, 56, 103, 511, "16:23:56.103511", "\249\076\246\079\131\211\236\064" ; 1, 23, 43, 300, 946, "01:23:43.300946", "\221\011\204\010\077\159\179\064" ; 13, 31, 56, 235, 603, "13:31:56.235603", "\123\077\015\138\135\201\231\064" ; 1, 9, 21, 279, 896, "01:09:21.279896", "\072\166\067\167\071\065\176\064" ; 13, 24, 24, 808, 97, "13:24:24.808097", "\095\061\238\219\025\145\231\064" ; 11, 32, 5, 90, 817, "11:32:05.090817", "\157\013\249\231\162\070\228\064" ; 2, 17, 41, 498, 833, "02:17:41.498833", "\149\126\194\217\191\034\192\064" ; 6, 18, 0, 124, 753, "06:18:00.124753", "\197\001\244\251\007\038\214\064" ; 20, 48, 10, 405, 194, "20:48:10.405194", "\040\180\172\123\166\072\242\064" ; 7, 44, 6, 43, 810, "07:44:06.043810", "\080\117\200\205\130\049\219\064" ; 21, 10, 21, 768, 836, "21:10:21.768836", "\064\250\038\077\220\155\242\064" ; 1, 42, 55, 125, 362, "01:42:55.125362", "\041\090\185\023\032\031\184\064" ; 23, 28, 40, 539, 8, "23:28:40.539008", "\069\218\198\159\136\162\244\064" ; 1, 40, 28, 685, 922, "01:40:28.685922", "\156\141\149\152\175\140\183\064" ; 2, 56, 50, 66, 509, "02:56:50.066509", "\242\237\093\131\008\185\196\064" ; 0, 24, 48, 298, 881, "00:24:48.298881", "\149\097\220\013\050\065\151\064" ; 23, 38, 55, 943, 591, "23:38:55.943591", "\093\224\242\024\255\200\244\064" ; 23, 53, 31, 764, 494, "23:53:31.764494", "\128\015\094\059\188\255\244\064" ; 13, 34, 28, 410, 660, "13:34:28.410660", "\185\112\032\036\141\220\231\064" ; 19, 10, 47, 332, 535, "19:10:47.332535", "\092\056\016\082\117\219\240\064" ; 14, 28, 26, 282, 228, "14:28:26.282228", "\192\003\003\008\073\113\233\064" ; 20, 4, 10, 448, 454, "20:04:10.448454", "\252\025\222\044\167\163\241\064" ; 3, 28, 49, 408, 589, "03:28:49.408589", "\064\244\164\076\180\120\200\064" ; 17, 45, 8, 3, 53, "17:45:08.003053", "\229\154\002\025\128\052\239\064" ; 12, 23, 19, 904, 563, "12:23:19.904563", "\198\026\046\242\252\198\229\064" ; 1, 51, 21, 993, 383, "01:51:21.993383", "\103\041\089\078\254\025\186\064" ; 15, 36, 46, 698, 13, "15:36:46.698013", "\229\091\031\086\214\113\235\064" ; 3, 49, 20, 154, 207, "03:49:20.154207", "\232\018\014\189\019\224\202\064" ; 5, 51, 55, 396, 807, "05:51:55.396807", "\245\047\073\101\217\158\212\064" ; 15, 41, 0, 203, 972, "15:41:00.203972", "\170\073\240\134\134\145\235\064" ; 2, 56, 9, 983, 960, "02:56:09.983960", "\073\186\102\242\253\164\196\064" ; 8, 28, 16, 249, 413, "08:28:16.249413", "\141\241\097\246\015\200\221\064" ; 7, 9, 46, 577, 236, "07:09:46.577236", "\133\067\111\241\164\046\217\064" ; 23, 44, 32, 296, 147, "23:44:32.296147", "\253\162\004\189\004\222\244\064" ; 6, 18, 47, 318, 825, "06:18:47.318825", "\009\249\160\103\212\049\214\064" ; 19, 26, 54, 749, 510, "19:26:54.749510", "\160\050\254\253\235\023\241\064" ; 7, 46, 6, 866, 726, "07:46:06.866726", "\038\084\112\120\183\079\219\064" ; 16, 55, 32, 556, 170, "16:55:32.556170", "\032\007\037\204\145\192\237\064" ; 17, 31, 38, 296, 129, "17:31:38.296129", "\077\134\227\121\073\207\238\064" ; 8, 14, 32, 908, 904, "08:14:32.908904", "\205\174\123\043\058\250\220\064" ; 7, 3, 29, 131, 650, "07:03:29.131650", "\034\031\244\108\072\208\216\064" ; 23, 27, 21, 833, 668, "23:27:21.833668", "\187\065\180\086\157\157\244\064" ; 1, 6, 9, 470, 67, "01:06:09.470067", "\219\047\159\172\240\002\175\064" ; 20, 34, 12, 467, 700, "20:34:12.467700", "\198\254\178\123\071\020\242\064" ; 6, 46, 7, 927, 311, "06:46:07.927311", "\142\060\016\089\251\203\215\064" ; 15, 35, 38, 549, 419, "15:35:38.549419", "\154\039\215\148\081\105\235\064" ; 21, 29, 4, 75, 256, "21:29:04.075256", "\173\162\063\052\001\226\242\064" ; 1, 48, 21, 871, 559, "01:48:21.871559", "\137\153\125\030\223\101\185\064" ; 19, 3, 8, 773, 799, "19:03:08.773799", "\107\015\123\097\204\190\240\064" ; 21, 18, 39, 183, 504, "21:18:39.183504", "\235\227\161\239\242\186\242\064" ; 7, 32, 26, 41, 571, "07:32:26.041571", "\094\105\025\169\130\130\218\064" ; 5, 14, 55, 489, 460, "05:14:55.489460", "\045\009\080\083\223\115\210\064" ; 18, 38, 8, 75, 622, "18:38:08.075622", "\014\106\191\053\001\097\240\064" ; 18, 30, 33, 591, 403, "18:30:33.591403", "\252\253\098\118\153\068\240\064" ; 13, 16, 8, 888, 638, "13:16:08.888638", "\127\245\184\111\028\083\231\064" ; 1, 46, 55, 515, 846, "01:46:55.515846", "\198\195\123\014\132\015\185\064" ; 11, 54, 3, 11, 548, "11:54:03.011548", "\075\233\153\094\096\235\228\064" ; 23, 29, 20, 892, 607, "23:29:20.892607", "\019\071\030\072\014\165\244\064" ; 16, 54, 47, 426, 881, "16:54:47.426881", "\201\087\002\169\237\186\237\064" ; 12, 30, 6, 186, 60, "12:30:06.186060", "\227\025\052\244\197\249\229\064" ; 23, 33, 10, 215, 130, "23:33:10.215130", "\166\039\044\113\099\179\244\064" ; 3, 3, 32, 520, 280, "03:03:32.520280", "\098\248\136\152\066\130\197\064" ; 4, 30, 42, 937, 748, "04:30:42.937748", "\242\095\032\008\120\185\207\064" ; 1, 47, 45, 334, 959, "01:47:45.334959", "\128\126\223\191\085\065\185\064" ; 3, 49, 1, 561, 671, "03:49:01.561671", "\014\216\213\228\199\214\202\064" ; 7, 18, 59, 706, 995, "07:18:59.706995", "\219\244\103\063\237\184\217\064" ; 23, 15, 5, 246, 479, "23:15:05.246479", "\194\246\147\241\147\111\244\064" ; 21, 39, 23, 45, 229, "21:39:23.045229", "\061\011\066\185\176\008\243\064" ; 12, 20, 25, 886, 917, "12:20:25.886917", "\168\194\159\097\060\177\229\064" ; 18, 38, 53, 189, 205, "18:38:53.189205", "\116\210\251\006\211\099\240\064" ; 21, 35, 8, 744, 950, "21:35:08.744950", "\243\176\080\235\203\248\242\064" ; 11, 6, 31, 521, 226, "11:06:31.521226", "\250\037\226\173\240\134\227\064" ; 5, 41, 9, 273, 774, "05:41:09.273774", "\032\098\131\133\081\253\211\064" ; 19, 50, 47, 428, 913, "19:50:47.428913", "\189\224\211\220\118\113\241\064" ; 11, 8, 43, 270, 643, "11:08:43.270643", "\060\130\027\169\104\151\227\064" ; 2, 45, 3, 101, 876, "02:45:03.101876", "\032\212\069\010\141\087\195\064" ; 13, 45, 14, 67, 414, "13:45:14.067414", "\170\103\065\040\066\045\232\064" ; 15, 50, 58, 696, 377, "15:50:58.696377", "\022\107\184\072\086\220\235\064" ; 22, 11, 24, 63, 986, "22:11:24.063986", "\022\047\022\006\193\128\243\064" ; 19, 53, 33, 824, 266, "19:53:33.824266", "\147\139\049\048\221\123\241\064" ; 9, 26, 46, 476, 547, "09:26:46.476547", "\129\126\223\063\207\154\224\064" ; 6, 38, 4, 396, 314, "06:38:04.396314", "\061\101\053\093\025\083\215\064" ; 3, 43, 7, 175, 879, "03:43:07.175879", "\134\252\051\131\150\037\202\064" ; 16, 8, 30, 772, 328, "16:08:30.772328", "\185\053\233\182\216\095\236\064" ; 9, 50, 50, 126, 169, "09:50:50.126169", "\024\146\147\009\068\079\225\064" ; 16, 23, 1, 810, 315, "16:23:01.810315", "\014\185\025\238\185\204\236\064" ; 16, 37, 54, 888, 959, "16:37:54.888959", "\015\037\090\114\092\060\237\064" ; 8, 21, 45, 209, 100, "08:21:45.209100", "\102\247\228\097\077\102\221\064" ; 22, 31, 43, 482, 305, "22:31:43.482305", "\155\114\133\183\247\204\243\064" ; 15, 33, 12, 131, 563, "15:33:12.131563", "\204\155\195\053\004\087\235\064" ; 23, 36, 18, 167, 246, "23:36:18.167246", "\070\036\010\173\034\191\244\064" ; 1, 26, 2, 204, 36, "01:26:02.204036", "\053\011\180\059\052\042\180\064" ; 5, 46, 54, 90, 918, "05:46:54.090918", "\040\187\153\209\133\083\212\064" ; 22, 10, 43, 588, 941, "22:10:43.588941", "\229\101\077\108\057\126\243\064" ; 14, 11, 27, 308, 579, "14:11:27.308579", "\039\017\225\223\233\241\232\064" ; 7, 11, 0, 509, 601, "07:11:00.509601", "\064\131\077\157\032\065\217\064" ; 17, 50, 42, 679, 877, "17:50:42.679877", "\009\105\141\193\085\094\239\064" ; 10, 41, 32, 454, 63, "10:41:32.454063", "\234\032\175\135\142\203\226\064" ; 23, 27, 13, 171, 786, "23:27:13.171786", "\063\173\162\191\018\157\244\064" ; 23, 17, 25, 899, 241, "23:17:25.899241", "\228\135\074\099\094\120\244\064" ; 2, 57, 11, 832, 355, "02:57:11.832355", "\213\207\155\138\234\195\196\064" ; 9, 56, 49, 179, 180, "09:56:49.179180", "\003\178\215\187\037\124\225\064" ; 7, 8, 51, 220, 592, "07:08:51.220592", "\113\232\045\030\206\032\217\064" ; 0, 31, 17, 793, 269, "00:31:17.793269", "\184\111\181\078\044\087\157\064" ; 10, 44, 34, 214, 215, "10:44:34.214215", "\106\106\217\218\070\226\226\064" ; 18, 10, 7, 891, 759, "18:10:07.891759", "\158\043\074\137\252\239\239\064" ; 4, 21, 14, 298, 901, "04:21:14.298901", "\223\081\099\066\038\157\206\064" ; 0, 19, 12, 994, 993, "00:19:12.994993", "\255\234\113\223\250\003\146\064" ; 6, 27, 25, 696, 383, "06:27:25.696383", "\159\000\138\145\108\179\214\064" ; 20, 30, 28, 774, 846, "20:30:28.774846", "\087\235\196\101\076\006\242\064" ; 17, 8, 5, 39, 53, "17:08:05.039053", "\186\019\236\063\161\030\238\064" ; 4, 25, 22, 896, 413, "04:25:22.896413", "\091\067\169\189\114\025\207\064" ; 11, 11, 46, 722, 634, "11:11:46.722634", "\160\086\209\031\087\174\227\064" ; 10, 46, 34, 261, 313, "10:46:34.261313", "\160\020\173\092\072\241\226\064" ; 1, 28, 25, 608, 526, "01:28:25.608526", "\196\036\092\200\155\185\180\064" ; 23, 17, 11, 333, 381, "23:17:11.333381", "\194\080\135\085\117\119\244\064" ; 17, 2, 45, 843, 712, "17:02:45.843712", "\232\078\176\255\186\246\237\064" ; 10, 58, 5, 482, 950, "10:58:05.482950", "\244\142\083\116\175\071\227\064" ; 10, 45, 29, 245, 273, "10:45:29.245273", "\051\195\070\217\039\233\226\064" ; 5, 47, 58, 980, 529, "05:47:58.980529", "\242\180\252\192\190\099\212\064" ; 19, 39, 14, 211, 19, "19:39:14.211019", "\125\117\085\096\035\070\241\064" ; 21, 43, 26, 336, 97, "21:43:26.336097", "\116\063\167\096\229\023\243\064" ; 4, 43, 10, 154, 302, "04:43:10.154302", "\237\126\021\224\137\151\208\064" ; 14, 13, 47, 10, 519, "14:13:47.010519", "\032\241\043\086\096\003\233\064" ; 17, 11, 6, 738, 657, "17:11:06.738657", "\062\001\020\163\087\053\238\064" ; 13, 12, 36, 790, 937, "13:12:36.790937", "\134\028\091\079\153\056\231\064" ; 16, 16, 57, 443, 472, "16:16:57.443472", "\022\049\236\048\046\159\236\064" ; 22, 29, 45, 849, 357, "22:29:45.849357", "\154\093\247\150\157\197\243\064" ; 12, 33, 10, 409, 475, "12:33:10.409475", "\177\080\107\026\205\016\230\064" ; 15, 28, 33, 582, 631, "15:28:33.582631", "\085\196\233\164\050\052\235\064" ; 3, 49, 1, 518, 112, "03:49:01.518112", "\213\119\126\081\194\214\202\064" ; 20, 53, 6, 46, 272, "20:53:06.046272", "\108\181\135\189\032\091\242\064" ; 2, 41, 55, 253, 691, "02:41:55.253691", "\037\090\242\120\160\249\194\064" ; 1, 8, 48, 470, 57, "01:08:48.470057", "\066\210\167\085\120\032\176\064" ; 17, 38, 8, 714, 391, "17:38:08.714391", "\178\131\074\220\022\000\239\064" ; 16, 8, 9, 91, 683, "16:08:09.091683", "\211\047\017\239\034\093\236\064" ; 18, 49, 3, 803, 830, "18:49:03.803830", "\153\216\124\220\252\137\240\064" ; 1, 20, 33, 153, 394, "01:20:33.153394", "\103\069\212\068\039\225\178\064" ; 13, 3, 30, 147, 847, "13:03:30.147847", "\186\161\041\187\068\244\230\064" ; 1, 12, 59, 620, 161, "01:12:59.620161", "\065\013\223\194\158\027\177\064" ; 11, 41, 9, 988, 915, "11:41:09.988915", "\240\017\049\165\191\138\228\064" ; 10, 35, 33, 622, 304, "10:35:33.622304", "\006\020\234\233\179\158\226\064" ; 15, 50, 57, 488, 627, "15:50:57.488627", "\030\023\213\162\047\220\235\064" ; 20, 49, 59, 681, 794, "20:49:59.681794", "\074\211\160\232\122\079\242\064" ; 21, 47, 15, 274, 676, "21:47:15.274676", "\080\169\018\101\052\038\243\064" ; 23, 25, 31, 618, 167, "23:25:31.618167", "\136\020\003\228\185\150\244\064" ; 18, 5, 17, 53, 707, "18:05:17.053707", "\018\190\247\183\161\203\239\064" ; 21, 14, 50, 79, 411, "21:14:50.079411", "\255\119\068\069\161\172\242\064" ; 9, 50, 21, 125, 443, "09:50:21.125443", "\208\009\161\003\164\075\225\064" ; 13, 45, 44, 241, 284, "13:45:44.241284", "\034\057\153\184\007\049\232\064" ; 10, 26, 44, 457, 74, "10:26:44.457074", "\060\167\089\160\142\092\226\064" ; 4, 26, 30, 513, 147, "04:26:30.513147", "\134\007\205\174\065\059\207\064" ; 20, 19, 24, 809, 635, "20:19:24.809635", "\107\212\067\244\204\220\241\064" ; 5, 40, 25, 271, 656, "05:40:25.271656", "\241\216\207\098\081\242\211\064" ; 22, 2, 2, 777, 351, "22:02:02.777351", "\040\154\007\112\172\093\243\064" ; 10, 40, 36, 685, 839, "10:40:36.685839", "\106\161\100\242\149\196\226\064" ; 14, 40, 20, 587, 243, "14:40:20.587243", "\250\212\177\202\146\202\233\064" ; 4, 56, 9, 163, 876, "04:56:09.163876", "\038\195\241\124\074\090\209\064" ; 0, 0, 3, 243, 224, "00:00:03.243224", "\132\209\172\108\031\242\009\064" ; 14, 46, 54, 536, 421, "14:46:54.536421", "\124\095\092\042\209\251\233\064" ; 17, 1, 3, 837, 654, "17:01:03.837654", "\236\194\015\206\250\233\237\064" ; 11, 42, 50, 475, 795, "11:42:50.475795", "\147\111\182\057\079\151\228\064" ; 10, 53, 43, 349, 708, "10:53:43.349708", "\229\212\206\048\235\038\227\064" ; 5, 28, 5, 782, 404, "05:28:05.782404", "\016\058\232\018\114\057\211\064" ; 7, 17, 13, 650, 288, "07:17:13.650288", "\063\143\081\158\105\158\217\064" ; 22, 26, 51, 201, 671, "22:26:51.201671", "\217\094\011\058\179\186\243\064" ; 5, 14, 2, 304, 721, "05:14:02.304721", "\090\130\140\128\147\102\210\064" ; 4, 41, 31, 887, 66, "04:41:31.887066", "\217\120\176\197\248\126\208\064" ; 20, 57, 53, 50, 969, "20:57:53.050969", "\194\222\196\208\016\109\242\064" ; 21, 53, 6, 751, 948, "21:53:06.751948", "\069\160\250\007\044\060\243\064" ; 2, 24, 35, 896, 84, "02:24:35.896084", "\060\105\225\178\242\241\192\064" ; 19, 21, 48, 357, 560, "19:21:48.357560", "\166\213\144\184\197\004\241\064" ; 7, 15, 1, 651, 352, "07:15:01.651352", "\140\076\192\175\105\125\217\064" ; 10, 50, 43, 901, 634, "10:50:43.901634", "\223\139\047\218\124\016\227\064" ; 3, 38, 57, 877, 529, "03:38:57.877529", "\038\202\222\082\240\168\201\064" ; 4, 47, 24, 426, 43, "04:47:24.426043", "\236\219\073\068\027\215\208\064" ; 7, 27, 10, 864, 779, "07:27:10.864779", "\210\004\138\088\183\051\218\064" ; 18, 14, 53, 205, 373, "18:14:53.205373", "\232\050\053\073\211\009\240\064" ; 0, 16, 46, 495, 792, "00:16:46.495792", "\243\204\203\097\247\115\143\064" ; 4, 0, 47, 628, 177, "04:00:47.628177", "\141\155\026\104\208\055\204\064" ; 2, 55, 30, 302, 153, "02:55:30.302153", "\178\018\243\172\038\145\196\064" ; 7, 28, 2, 970, 405, "07:28:02.970405", "\184\146\029\027\190\064\218\064" ; 19, 50, 42, 61, 235, "19:50:42.061235", "\038\141\209\250\032\113\241\064" ; 17, 19, 26, 936, 60, "17:19:26.936060", "\227\025\052\244\221\115\238\064" ; 9, 12, 18, 0, 711, "09:12:18.000711", "\056\019\211\005\064\046\224\064" ; 15, 42, 11, 173, 897, "15:42:11.173897", "\252\112\144\144\101\154\235\064" ; 1, 55, 15, 521, 176, "01:55:15.521176", "\117\083\202\107\133\003\187\064" ; 23, 6, 1, 510, 856, "23:06:01.510856", "\079\087\119\044\152\077\244\064" ; 11, 19, 58, 960, 58, "11:19:58.960058", "\008\142\203\184\222\235\227\064" ; 12, 14, 56, 898, 856, "12:14:56.898856", "\122\168\109\195\028\136\229\064" ; 12, 25, 6, 973, 406, "12:25:06.973406", "\247\086\036\038\095\212\229\064" ; 19, 46, 57, 833, 592, "19:46:57.833592", "\163\144\100\086\029\099\241\064" ; 2, 24, 13, 505, 151, "02:24:13.505151", "\069\184\201\168\192\230\192\064" ; 9, 19, 10, 258, 978, "09:19:10.258978", "\012\059\140\073\200\097\224\064" ; 16, 12, 17, 672, 770, "16:12:17.672770", "\119\243\084\135\053\124\236\064" ; 6, 58, 54, 213, 451, "06:58:54.213451", "\019\098\046\169\141\139\216\064" ; 8, 34, 4, 182, 870, "08:34:04.182870", "\091\095\036\180\011\031\222\064" ; 17, 51, 13, 980, 176, "17:51:13.980176", "\011\015\154\093\063\098\239\064" ; 16, 23, 34, 695, 193, "16:23:34.695193", "\237\099\005\063\214\208\236\064" ; 1, 40, 36, 539, 274, "01:40:36.539274", "\149\097\220\013\138\148\183\064" ; 5, 8, 46, 233, 68, "05:08:46.233068", "\112\011\150\234\142\023\210\064" ; 20, 46, 19, 552, 770, "20:46:19.552770", "\003\091\037\216\184\065\242\064" ; 14, 35, 24, 1, 379, "14:35:24.001379", "\252\248\075\011\128\165\233\064" ; 11, 34, 46, 323, 942, "11:34:46.323942", "\249\156\187\093\202\090\228\064" ; 23, 8, 4, 505, 922, "23:08:04.505922", "\198\170\065\024\072\085\244\064" ; 8, 40, 8, 847, 481, "08:40:08.847481", "\191\242\032\061\054\122\222\064" ; 18, 9, 43, 445, 70, "18:09:43.445070", "\206\112\003\062\238\236\239\064" ; 10, 37, 14, 753, 528, "10:37:14.753528", "\147\192\230\028\088\171\226\064" ; 21, 49, 8, 59, 991, "21:49:08.059991", "\112\031\185\245\064\045\243\064" ; 12, 3, 22, 170, 867, "12:03:22.170867", "\031\018\190\119\069\049\229\064" ; 12, 22, 16, 142, 457, "12:22:16.142457", "\131\251\001\143\004\191\229\064" ; 7, 53, 17, 464, 529, "07:53:17.464529", "\195\215\215\186\093\187\219\064" ; 18, 29, 44, 133, 98, "18:29:44.133098", "\083\094\043\033\130\065\240\064" ; 4, 10, 57, 861, 879, "04:10:57.861879", "\014\019\013\082\238\104\205\064" ; 18, 41, 53, 140, 939, "18:41:53.140939", "\188\064\073\065\018\111\240\064" ; 8, 20, 32, 120, 908, "08:20:32.120908", "\117\232\244\188\007\084\221\064" ; 0, 24, 54, 97, 502, "00:24:54.097502", "\046\117\144\215\099\088\151\064" ; 23, 5, 27, 919, 819, "23:05:27.919819", "\179\032\148\183\126\075\244\064" ; 4, 22, 47, 675, 470, "04:22:47.675470", "\183\011\205\117\214\203\206\064" ; 13, 54, 8, 72, 470, "13:54:08.072470", "\254\154\172\081\002\112\232\064" ; 8, 59, 21, 98, 925, "08:59:21.098925", "\241\133\201\084\070\154\223\064" ; 20, 49, 28, 194, 614, "20:49:28.194614", "\214\145\035\029\131\077\242\064" ; 21, 43, 7, 431, 111, "21:43:07.431111", "\223\165\212\229\182\022\243\064" ; 10, 23, 55, 887, 100, "10:23:55.887100", "\009\138\031\099\124\071\226\064" ; 22, 2, 14, 51, 952, "22:02:14.051952", "\208\158\203\212\096\094\243\064" ; 20, 11, 46, 65, 381, "20:11:46.065381", "\141\242\204\011\033\192\241\064" ; 2, 31, 12, 899, 583, "02:31:12.899583", "\132\038\137\037\115\184\193\064" ; 2, 17, 58, 717, 57, "02:17:58.717057", "\047\022\134\200\091\043\192\064" ; 1, 15, 23, 703, 23, "01:15:23.703023", "\086\185\080\249\179\171\177\064" ; 15, 57, 30, 859, 42, "15:57:30.859042", "\252\165\069\125\091\013\236\064" ; 9, 22, 39, 265, 871, "09:22:39.265871", "\062\230\003\130\232\123\224\064" ; 12, 36, 32, 86, 986, "12:36:32.086986", "\039\221\150\200\002\042\230\064" ; 1, 4, 20, 699, 272, "01:04:20.699272", "\005\198\250\006\102\041\174\064" ; 2, 21, 42, 365, 461, "02:21:42.365461", "\123\017\109\199\046\155\192\064" ; 18, 56, 29, 760, 561, "18:56:29.760561", "\217\002\066\043\220\165\240\064" ; 18, 25, 52, 469, 285, "18:25:52.469285", "\248\252\048\130\007\051\240\064" ; 6, 14, 4, 433, 556, "06:14:04.433556", "\063\170\097\191\027\235\213\064" ; 1, 18, 47, 39, 516, "01:18:47.039516", "\171\119\184\029\010\119\178\064" ; 1, 20, 13, 701, 39, "01:20:13.701039", "\056\186\074\119\179\205\178\064" ; 3, 50, 21, 953, 118, "03:50:21.953118", "\157\071\197\255\249\254\202\064" ; 17, 57, 32, 825, 619, "17:57:32.825619", "\126\137\120\107\154\145\239\064" ; 7, 9, 22, 308, 668, "07:09:22.308668", "\085\109\055\193\147\040\217\064" ; 2, 20, 5, 855, 34, "02:20:05.855034", "\124\013\193\113\237\106\192\064" ; 7, 14, 17, 325, 584, "07:14:17.325584", "\007\070\094\214\084\114\217\064" ; 4, 47, 11, 393, 172, "04:47:11.393172", "\109\228\186\041\217\211\208\064" ; 11, 46, 45, 84, 165, "11:46:45.084165", "\079\204\122\177\162\180\228\064" ; 13, 55, 11, 499, 982, "13:55:11.499982", "\083\064\218\255\239\119\232\064" ; 14, 39, 35, 492, 346, "14:39:35.492346", "\010\102\076\193\239\196\233\064" ; 2, 11, 15, 627, 282, "02:11:15.627282", "\095\155\141\149\160\195\190\064" ; 15, 27, 17, 582, 909, "15:27:17.582909", "\114\198\048\167\178\042\235\064" ; 12, 37, 54, 464, 267, "12:37:54.464267", "\180\119\070\219\078\052\230\064" ; 1, 15, 36, 79, 435, "01:15:36.079435", "\040\039\218\085\020\184\177\064" ; 7, 32, 2, 798, 660, "07:32:02.798660", "\040\213\062\029\179\124\218\064" ; 9, 9, 27, 463, 661, "09:09:27.463661", "\238\151\079\214\238\024\224\064" ; 18, 31, 41, 670, 663, "18:31:41.670663", "\058\032\009\187\218\072\240\064" ; 9, 2, 21, 805, 264, "09:02:21.805264", "\041\004\114\137\115\199\223\064" ; 7, 15, 33, 495, 195, "07:15:33.495195", "\137\094\070\177\095\133\217\064" ; 16, 23, 41, 955, 474, "16:23:41.955474", "\198\053\062\147\190\209\236\064" ; 19, 44, 15, 603, 225, "19:44:15.603225", "\242\065\207\166\249\088\241\064" ; 3, 12, 31, 819, 487, "03:12:31.819487", "\063\052\243\228\232\143\198\064" ; 13, 28, 21, 841, 5, "13:28:21.841005", "\089\081\131\233\186\174\231\064" ; 2, 2, 18, 761, 836, "02:02:18.761836", "\235\032\175\007\195\170\188\064" ; 7, 56, 21, 539, 911, "07:56:21.539911", "\240\221\230\141\098\233\219\064" ; 18, 52, 54, 212, 517, "18:52:54.212517", "\205\057\120\102\099\152\240\064" ; 13, 45, 21, 979, 586, "13:45:21.979586", "\052\189\196\088\063\046\232\064" ; 5, 39, 55, 213, 892, "05:39:55.213892", "\056\018\104\176\205\234\211\064" ; 4, 26, 41, 406, 375, "04:26:41.406375", "\117\147\024\004\180\064\207\064" ; 21, 51, 3, 111, 311, "21:51:03.111311", "\011\011\238\199\113\052\243\064" ; 8, 22, 32, 550, 517, "08:22:32.550517", "\185\167\171\059\035\114\221\064" ; 21, 19, 49, 381, 410, "21:19:49.381410", "\069\095\065\026\086\191\242\064" ; 11, 1, 10, 987, 757, "11:01:10.987757", "\109\145\180\155\223\094\227\064" ; 21, 59, 30, 553, 22, "21:59:30.553022", "\191\152\045\217\040\084\243\064" ; 5, 51, 25, 865, 941, "05:51:25.865941", "\209\204\147\107\119\151\212\064" ; 18, 44, 38, 582, 208, "18:44:38.582208", "\247\085\185\080\105\121\240\064" ; 0, 43, 22, 578, 920, "00:43:22.578920", "\000\198\051\104\040\085\164\064" ; 4, 33, 0, 225, 889, "04:33:00.225889", "\196\069\238\233\028\254\207\064" ; 19, 44, 42, 221, 308, "19:44:42.221308", "\230\065\122\138\163\090\241\064" ; 14, 27, 15, 543, 424, "14:27:15.543424", "\123\186\186\099\113\104\233\064" ; 6, 59, 36, 629, 330, "06:59:36.629330", "\025\086\241\070\040\150\216\064" ; 10, 22, 37, 949, 428, "10:22:37.949428", "\061\212\182\097\190\061\226\064" ; 2, 5, 49, 31, 354, "02:05:49.031354", "\153\212\208\006\008\125\189\064" ; 8, 53, 49, 553, 878, "08:53:49.553878", "\254\181\188\114\099\071\223\064" ; 15, 3, 31, 159, 555, "15:03:31.159555", "\093\022\019\027\101\120\234\064" ; 14, 50, 41, 871, 452, "14:50:41.871452", "\001\078\239\226\059\024\234\064" ; 14, 7, 24, 707, 552, "14:07:24.707552", "\135\023\068\164\150\211\232\064" ; 19, 59, 5, 733, 474, "19:59:05.733474", "\167\059\079\188\155\144\241\064" ; 22, 37, 47, 695, 653, "22:37:47.695653", "\070\010\101\033\187\227\243\064" ; 5, 5, 0, 972, 806, "05:05:00.972806", "\215\024\116\066\062\223\209\064" ; 12, 44, 35, 693, 912, "12:44:35.693912", "\074\240\134\052\118\102\230\064" ; 2, 21, 10, 138, 976, "02:21:10.138976", "\119\047\247\201\017\139\192\064" ; 14, 38, 29, 848, 127, "14:38:29.848127", "\251\059\219\035\187\188\233\064" ; 22, 11, 55, 30, 864, "22:11:55.030864", "\234\063\107\126\176\130\243\064" ; 11, 19, 53, 707, 248, "11:19:53.707248", "\197\142\198\161\054\235\227\064" ; 20, 41, 20, 489, 15, "20:41:20.489015", "\132\100\001\211\007\047\242\064" ; 23, 56, 57, 993, 952, "23:56:57.993952", "\093\054\058\231\159\012\245\064" ; 21, 35, 5, 506, 458, "21:35:05.506458", "\044\180\115\026\152\248\242\064" ; 4, 46, 42, 263, 632, "04:46:42.263632", "\139\192\088\223\144\204\208\064" ; 21, 50, 28, 195, 312, "21:50:28.195312", "\201\121\255\031\067\050\243\064" ; 13, 24, 51, 727, 236, "13:24:51.727236", "\143\110\132\069\119\148\231\064" ; 9, 6, 20, 463, 552, "09:06:20.463552", "\000\001\107\213\142\001\224\064" ; 11, 40, 7, 617, 573, "11:40:07.617573", "\188\115\040\195\243\130\228\064" ; 21, 26, 37, 284, 263, "21:26:37.284263", "\007\092\087\140\212\216\242\064" ; 11, 55, 41, 796, 695, "11:55:41.796695", "\061\131\134\126\185\247\228\064" ; 7, 48, 18, 239, 740, "07:48:18.239740", "\227\112\230\087\143\112\219\064" ; 8, 47, 34, 675, 706, "08:47:34.675706", "\237\096\196\062\171\233\222\064" ; 3, 9, 9, 907, 607, "03:09:09.907607", "\079\087\119\044\244\042\198\064" ; 22, 2, 0, 199, 663, "22:02:00.199663", "\115\212\209\049\131\093\243\064" ; 18, 46, 34, 449, 511, "18:46:34.449511", "\067\114\050\049\167\128\240\064" ; 22, 1, 58, 781, 889, "22:01:58.781889", "\066\010\158\130\108\093\243\064" ; 16, 8, 42, 615, 665, "16:08:42.615665", "\009\022\135\179\083\097\236\064" ; 22, 46, 34, 736, 61, "22:46:34.736061", "\046\230\231\198\171\004\244\064" ; 10, 0, 21, 282, 669, "10:00:21.282669", "\211\219\159\011\169\150\225\064" ; 10, 56, 15, 445, 641, "10:56:15.445641", "\024\234\176\066\238\057\227\064" ; 14, 24, 11, 153, 965, "14:24:11.153965", "\247\001\072\237\100\081\233\064" ; 2, 13, 26, 190, 581, "02:13:26.190581", "\061\154\234\201\048\070\191\064" ; 3, 37, 42, 72, 160, "03:37:42.072160", "\010\244\137\060\009\131\201\064" ; 9, 36, 5, 859, 663, "09:36:05.859663", "\210\250\091\130\187\224\224\064" ; 18, 29, 1, 350, 869, "18:29:01.350869", "\003\208\040\157\213\062\240\064" ; 10, 49, 6, 616, 918, "10:49:06.616918", "\074\209\202\189\083\004\227\064" ; 10, 44, 17, 906, 385, "10:44:17.906385", "\147\029\027\001\061\224\226\064" ; 13, 41, 42, 592, 335, "13:41:42.592335", "\168\135\104\244\210\018\232\064" ; 1, 56, 10, 28, 923, "01:56:10.028923", "\026\107\127\103\007\058\187\064" ; 7, 39, 52, 212, 56, "07:39:52.212056", "\059\084\083\146\013\242\218\064" ; 4, 3, 22, 521, 228, "04:03:22.521228", "\226\094\153\183\066\133\204\064" ; 10, 45, 27, 842, 882, "10:45:27.842882", "\012\172\227\248\250\232\226\064" ; 5, 41, 21, 805, 17, "05:41:21.805017", "\238\005\102\133\115\000\212\064" ; 5, 16, 44, 698, 518, "05:16:44.698518", "\107\215\132\180\044\143\210\064" ; 7, 49, 10, 55, 97, "07:49:10.055097", "\071\145\181\134\131\125\219\064" ; 8, 3, 9, 795, 69, "08:03:09.795069", "\068\022\105\226\114\079\220\064" ; 20, 33, 9, 122, 328, "20:33:09.122328", "\118\052\014\245\081\016\242\064" ; 0, 51, 4, 817, 511, "00:51:04.817511", "\062\066\205\144\162\241\167\064" ; 1, 54, 53, 990, 104, "01:54:53.990104", "\163\171\116\119\253\237\186\064" ; 3, 20, 35, 658, 889, "03:20:35.658889", "\089\137\121\086\212\129\199\064" ; 14, 19, 44, 545, 845, "14:19:44.545845", "\246\238\143\119\017\048\233\064" ; 11, 18, 29, 271, 85, "11:18:29.271085", "\046\115\186\172\168\224\227\064" ; 8, 25, 3, 859, 330, "08:25:03.859330", "\158\065\067\255\246\151\221\064" ; 4, 42, 56, 947, 152, "04:42:56.947152", "\022\108\035\158\060\148\208\064" ; 5, 11, 22, 548, 941, "05:11:22.548941", "\155\110\217\033\163\062\210\064" ; 11, 4, 24, 596, 33, "11:04:24.596033", "\074\204\179\018\019\119\227\064" ; 16, 34, 53, 101, 960, "16:34:53.101960", "\048\158\065\067\163\037\237\064" ; 16, 4, 49, 367, 211, "16:04:49.367211", "\119\072\049\192\043\068\236\064" ; 16, 5, 27, 296, 139, "16:05:27.296139", "\003\127\248\121\233\072\236\064" ; 16, 30, 12, 449, 977, "16:30:12.449977", "\095\042\054\102\142\002\237\064" ; 1, 17, 36, 41, 268, "01:17:36.041268", "\095\038\138\144\010\048\178\064" ; 22, 21, 7, 320, 702, "22:21:07.320702", "\157\107\152\033\053\165\243\064" ; 7, 28, 44, 801, 697, "07:28:44.801697", "\019\239\000\079\051\075\218\064" ; 2, 45, 34, 576, 810, "02:45:34.576810", "\000\251\232\212\073\103\195\064" ; 23, 47, 9, 915, 462, "23:47:09.915462", "\107\123\187\165\222\231\244\064" ; 23, 39, 37, 565, 902, "23:39:37.565902", "\108\065\239\013\153\203\244\064" ; 23, 0, 0, 667, 890, "23:00:00.667890", "\181\108\173\175\010\055\244\064" ; 4, 52, 15, 643, 788, "04:52:15.643788", "\100\149\210\051\233\031\209\064" ; 15, 49, 32, 506, 821, "15:49:32.506821", "\126\172\224\055\144\209\235\064" ; 4, 35, 5, 602, 314, "04:35:05.602314", "\251\004\080\140\102\030\208\064" ; 2, 51, 20, 551, 788, "02:51:20.551788", "\041\059\253\160\070\020\196\064" ; 14, 45, 18, 129, 847, "14:45:18.129847", "\080\229\180\039\196\239\233\064" ; 8, 39, 4, 582, 929, "08:39:04.582929", "\185\111\181\078\037\106\222\064" ; 18, 52, 40, 832, 311, "18:52:40.832311", "\209\086\037\081\141\151\240\064" ; 0, 19, 33, 352, 727, "00:19:33.352727", "\171\069\068\049\105\085\146\064" ; 4, 22, 24, 687, 440, "04:22:24.687440", "\251\174\008\254\087\192\206\064" ; 21, 1, 5, 172, 190, "21:01:05.172190", "\044\077\074\193\018\121\242\064" ; 13, 37, 34, 195, 350, "13:37:34.195350", "\169\164\078\064\198\243\231\064" ; 9, 50, 21, 588, 255, "09:50:21.588255", "\087\038\252\210\178\075\225\064" ; 3, 9, 31, 737, 370, "03:09:31.737370", "\134\225\035\098\222\053\198\064" ; 4, 8, 22, 188, 137, "04:08:22.188137", "\022\139\223\020\024\027\205\064" ; 16, 26, 58, 56, 791, "16:26:58.056791", "\246\091\059\209\065\234\236\064" ; 8, 42, 25, 374, 48, "08:42:25.374048", "\201\005\103\240\087\156\222\064" ; 13, 46, 7, 838, 124, "13:46:07.838124", "\064\108\233\209\250\051\232\064" ; 19, 6, 46, 366, 133, "19:06:46.366133", "\207\070\174\219\101\204\240\064" ; 9, 25, 4, 443, 650, "09:25:04.443650", "\028\124\097\050\014\142\224\064" ; 4, 39, 34, 969, 75, "04:39:34.969075", "\024\038\083\005\190\097\208\064" ; 19, 7, 37, 899, 413, "19:07:37.899413", "\202\226\254\099\158\207\240\064" ; 19, 26, 35, 633, 96, "19:26:35.633096", "\116\069\041\033\186\022\241\064" ; 8, 50, 27, 113, 959, "08:50:27.113959", "\134\176\026\075\199\020\223\064" ; 8, 43, 9, 770, 877, "08:43:09.770877", "\015\124\012\086\113\167\222\064" ; 23, 26, 24, 684, 861, "23:26:24.684861", "\212\206\048\245\010\154\244\064" ; 21, 28, 35, 472, 799, "21:28:35.472799", "\041\175\149\144\055\224\242\064" ; 0, 13, 8, 513, 552, "00:13:08.513552", "\093\166\038\193\027\164\136\064" ; 9, 18, 41, 986, 265, "09:18:41.986265", "\006\158\123\143\063\094\224\064" ; 18, 26, 35, 486, 585, "18:26:35.486585", "\092\090\013\201\183\053\240\064" ; 3, 21, 29, 806, 312, "03:21:29.806312", "\048\075\059\053\231\156\199\064" ; 6, 56, 25, 461, 260, "06:56:25.461260", "\189\169\072\133\093\102\216\064" ; 0, 40, 25, 913, 351, "00:40:25.913351", "\138\005\190\162\211\243\162\064" ; 11, 49, 7, 794, 680, "11:49:07.794680", "\089\192\004\110\121\198\228\064" ; 9, 15, 59, 106, 407, "09:15:59.106407", "\034\167\175\103\227\073\224\064" ; 2, 0, 56, 56, 97, "02:00:56.056097", "\103\124\095\092\014\088\188\064" ; 21, 5, 52, 363, 396, "21:05:52.363396", "\248\082\120\208\005\139\242\064" ; 6, 2, 42, 96, 108, "06:02:42.096108", "\057\043\162\038\134\064\213\064" ; 2, 47, 57, 155, 666, "02:47:57.155666", "\141\013\221\236\147\174\195\064" ; 22, 32, 8, 762, 591, "22:32:08.762591", "\212\158\146\051\140\206\243\064" ; 22, 25, 16, 845, 399, "22:25:16.845399", "\017\026\193\134\205\180\243\064" ; 8, 52, 18, 578, 640, "08:52:18.578640", "\010\017\112\008\165\048\223\064" ; 13, 22, 26, 845, 253, "13:22:26.845253", "\251\004\080\012\091\130\231\064" ; 13, 4, 4, 397, 391, "13:04:04.397391", "\151\084\109\183\140\248\230\064" ; 11, 11, 6, 576, 687, "11:11:06.576687", "\161\075\056\116\082\169\227\064" ; 19, 59, 22, 457, 445, "19:59:22.457445", "\043\217\177\081\167\145\241\064" ; 2, 9, 52, 849, 147, "02:09:52.849147", "\127\162\178\097\217\112\190\064" ; 14, 49, 17, 509, 821, "14:49:17.509821", "\058\033\116\080\176\013\234\064" ; 10, 29, 54, 405, 102, "10:29:54.405102", "\049\120\152\246\076\116\226\064" ; 11, 46, 52, 235, 240, "11:46:52.235240", "\087\009\022\135\135\181\228\064" ; 4, 57, 13, 995, 578, "04:57:13.995578", "\167\201\140\183\127\106\209\064" ; 10, 0, 34, 928, 83, "10:00:34.928083", "\159\030\219\178\093\152\225\064" ; 16, 35, 55, 771, 182, "16:35:55.771182", "\169\223\133\173\120\045\237\064" ; 23, 14, 20, 773, 207, "23:14:20.773207", "\161\077\014\095\204\108\244\064" ; 5, 24, 37, 746, 921, "05:24:37.746921", "\236\188\141\205\111\005\211\064" ; 23, 59, 16, 392, 694, "23:59:16.392694", "\246\128\121\072\070\021\245\064" ; 1, 26, 15, 980, 703, "01:26:15.980703", "\022\016\090\015\251\055\180\064" ; 14, 2, 52, 268, 650, "14:02:52.268650", "\130\226\199\152\136\177\232\064" ; 12, 20, 3, 973, 976, "12:20:03.973976", "\099\183\207\042\127\174\229\064" ; 3, 36, 26, 514, 762, "03:36:26.514762", "\156\161\184\227\065\093\201\064" ; 6, 18, 18, 725, 902, "06:18:18.725902", "\134\169\045\117\174\042\214\064" ; 16, 55, 12, 800, 337, "16:55:12.800337", "\025\087\092\156\025\190\237\064" ; 17, 21, 11, 887, 475, "17:21:11.887475", "\161\248\049\102\252\128\238\064" ; 5, 21, 42, 888, 788, "05:21:42.888788", "\069\016\231\225\184\217\210\064" ; 18, 8, 36, 682, 211, "18:08:36.682211", "\191\041\172\212\149\228\239\064" ; 6, 39, 33, 78, 259, "06:39:33.078259", "\104\009\050\002\069\105\215\064" ; 20, 23, 13, 441, 837, "20:23:13.441837", "\147\172\195\017\023\235\241\064" ; 3, 55, 12, 858, 868, "03:55:12.858868", "\202\249\098\239\109\144\203\064" ; 19, 15, 41, 673, 374, "19:15:41.673374", "\191\208\035\198\218\237\240\064" ; 7, 40, 19, 12, 877, "07:40:19.012877", "\119\013\250\210\192\248\218\064" ; 17, 59, 36, 303, 329, "17:59:36.303329", "\222\004\223\180\009\161\239\064" ; 1, 50, 10, 22, 195, "01:50:10.022195", "\034\079\146\174\005\210\185\064" ; 16, 31, 35, 439, 693, "16:31:35.439693", "\233\013\247\017\238\012\237\064" ; 17, 12, 38, 88, 235, "17:12:38.088235", "\236\052\210\210\194\064\238\064" ; 2, 17, 58, 201, 678, "02:17:58.201678", "\041\175\149\208\025\043\192\064" ; 20, 4, 1, 922, 353, "20:04:01.922353", "\038\056\245\193\030\163\241\064" ; 21, 49, 40, 936, 599, "21:49:40.936599", "\168\059\079\252\078\047\243\064" ; 18, 25, 39, 420, 650, "18:25:39.420650", "\145\126\251\186\054\050\240\064" ; 17, 23, 24, 790, 361, "17:23:24.790361", "\225\038\163\074\153\145\238\064" ; 11, 8, 14, 643, 141, "11:08:14.643141", "\054\111\156\148\212\147\227\064" ; 13, 59, 32, 331, 284, "13:59:32.331284", "\054\231\224\153\138\152\232\064" ; 7, 49, 9, 708, 368, "07:49:09.708368", "\098\188\230\085\109\125\219\064" ; 15, 49, 29, 608, 64, "15:49:29.608064", "\060\162\066\117\051\209\235\064" ; 5, 44, 31, 134, 597, "05:44:31.134597", "\072\188\060\157\200\047\212\064" ; 8, 52, 8, 933, 823, "08:52:08.933823", "\080\139\193\195\059\046\223\064" ; 4, 8, 21, 706, 38, "04:08:21.706038", "\222\003\116\095\218\026\205\064" ; 3, 26, 10, 290, 543, "03:26:10.290543", "\139\085\131\048\037\041\200\064" ; 4, 23, 29, 24, 49, "04:23:29.024049", "\064\162\009\020\131\224\206\064" ; 22, 7, 7, 798, 330, "22:07:07.798330", "\150\173\245\197\188\112\243\064" ; 23, 31, 2, 639, 303, "23:31:02.639303", "\083\200\149\058\106\171\244\064" ; 23, 15, 19, 184, 471, "23:15:19.184471", "\001\221\151\243\114\112\244\064" ; 11, 45, 0, 337, 781, "11:45:00.337781", "\135\025\026\207\138\167\228\064" ; 14, 41, 30, 812, 354, "14:41:30.812354", "\217\208\205\254\089\211\233\064" ; 23, 25, 34, 763, 772, "23:25:34.763772", "\026\253\104\056\236\150\244\064" ; 14, 3, 47, 217, 34, "14:03:47.217034", "\131\073\241\241\102\184\232\064" ; 21, 59, 55, 815, 117, "21:59:55.815117", "\151\031\184\010\189\085\243\064" ; 4, 0, 42, 751, 634, "04:00:42.751634", "\072\252\138\053\096\053\204\064" ; 22, 9, 11, 710, 463, "22:09:11.710463", "\097\115\014\094\123\120\243\064" ; 13, 31, 39, 820, 926, "13:31:39.820926", "\078\154\006\069\122\199\231\064" ; 10, 38, 30, 236, 315, "10:38:30.236315", "\145\121\228\143\199\180\226\064" ; 23, 28, 42, 282, 234, "23:28:42.282234", "\126\204\007\132\164\162\244\064" ; 21, 2, 24, 21, 643, "21:02:24.021643", "\147\084\166\088\000\126\242\064" ; 16, 56, 0, 193, 994, "16:56:00.193994", "\180\231\050\053\006\196\237\064" ; 16, 11, 25, 237, 864, "16:11:25.237864", "\157\246\148\156\167\117\236\064" ; 15, 23, 48, 261, 548, "15:23:48.261548", "\075\233\153\094\136\016\235\064" ; 4, 7, 21, 237, 26, "04:07:21.237026", "\038\051\222\086\158\252\204\064" ; 3, 50, 8, 307, 50, "03:50:08.307050", "\031\022\106\077\039\248\202\064" ; 15, 40, 52, 910, 677, "15:40:52.910677", "\136\023\068\036\157\144\235\064" ; 19, 51, 32, 554, 733, "19:51:32.554733", "\208\181\047\224\072\116\241\064" ; 11, 52, 19, 685, 685, "11:52:19.685685", "\075\171\033\241\117\222\228\064" ; 23, 33, 43, 864, 78, "23:33:43.864078", "\243\115\067\211\125\181\244\064" ; 2, 28, 43, 789, 421, "02:28:43.789421", "\228\080\191\011\229\109\193\064" ; 5, 42, 11, 435, 361, "05:42:11.435361", "\061\098\244\220\219\012\212\064" ; 5, 59, 22, 493, 977, "05:59:22.493977", "\254\180\081\157\159\014\213\064" ; 0, 15, 42, 944, 354, "00:15:42.944354", "\198\078\120\009\142\119\141\064" ; 11, 35, 8, 944, 410, "11:35:08.944410", "\001\082\155\056\158\093\228\064" ; 16, 12, 57, 473, 540, "16:12:57.473540", "\171\091\061\039\047\129\236\064" ; 15, 11, 26, 2, 606, "15:11:26.002606", "\153\045\089\021\192\179\234\064" ; 13, 48, 43, 494, 723, "13:48:43.494723", "\050\084\197\212\111\071\232\064" ; 12, 8, 13, 783, 306, "12:08:13.783306", "\153\190\215\016\185\085\229\064" ; 11, 20, 51, 233, 725, "11:20:51.233725", "\232\217\172\122\103\242\227\064" ; 15, 53, 50, 541, 183, "15:53:50.541183", "\196\002\095\081\209\241\235\064" ; 2, 5, 59, 282, 443, "02:05:59.282443", "\252\055\047\078\072\135\189\064" ; 22, 49, 5, 871, 397, "22:49:05.871397", "\013\251\061\241\029\014\244\064" ; 19, 58, 6, 637, 858, "19:58:06.637858", "\024\151\170\052\234\140\241\064" ; 11, 45, 55, 220, 356, "11:45:55.220356", "\175\006\040\013\103\174\228\064" ; 16, 46, 47, 749, 145, "16:46:47.749145", "\095\239\254\248\247\126\237\064" ; 4, 29, 17, 483, 407, "04:29:17.483407", "\212\211\071\224\189\142\207\064" ; 22, 39, 41, 817, 580, "22:39:41.817580", "\030\196\206\020\221\234\243\064" ; 4, 30, 57, 864, 164, "04:30:57.864164", "\048\011\237\156\238\192\207\064" ; 9, 8, 46, 931, 934, "09:08:46.931934", "\129\064\103\210\221\019\224\064" ; 22, 56, 3, 577, 696, "22:56:03.577696", "\049\041\062\062\057\040\244\064" ; 10, 0, 54, 522, 68, "10:00:54.522068", "\073\243\199\180\208\154\225\064" ; 20, 39, 1, 433, 296, "20:39:01.433296", "\088\201\199\238\086\038\242\064" ; 15, 47, 57, 50, 920, "15:47:57.050920", "\215\250\034\161\161\197\235\064" ; 9, 38, 14, 741, 643, "09:38:14.741643", "\202\025\138\187\215\240\224\064" ; 20, 5, 19, 116, 438, "20:05:19.116438", "\160\023\238\220\241\167\241\064" ; 20, 35, 41, 902, 72, "20:35:41.902072", "\170\012\227\110\222\025\242\064" ; 19, 44, 29, 544, 54, "19:44:29.544054", "\148\247\113\180\216\089\241\064" ; 4, 1, 31, 642, 454, "04:01:31.642454", "\152\195\238\059\210\077\204\064" ; 17, 58, 20, 747, 571, "17:58:20.747571", "\142\004\026\236\151\151\239\064" ; 10, 59, 54, 319, 497, "10:59:54.319497", "\198\197\081\057\074\085\227\064" ; 12, 50, 31, 133, 797, "12:50:31.133797", "\106\165\016\072\228\146\230\064" ; 15, 36, 17, 342, 287, "15:36:17.342287", "\219\221\003\244\042\110\235\064" ; 3, 55, 8, 599, 903, "03:55:08.599903", "\227\026\159\201\076\142\203\064" ; 4, 1, 29, 349, 329, "04:01:29.349329", "\070\011\208\182\172\076\204\064" ; 18, 59, 11, 622, 707, "18:59:11.622707", "\128\157\155\246\249\175\240\064" ; 6, 59, 39, 280, 666, "06:59:39.280666", "\198\134\110\246\209\150\216\064" ; 15, 29, 42, 316, 113, "15:29:42.316113", "\155\002\153\029\202\060\235\064" ; 3, 21, 4, 734, 758, "03:21:04.734758", "\061\214\140\012\094\144\199\064" ; 15, 17, 43, 516, 4, "15:17:43.516004", "\020\210\026\131\240\226\234\064" ; 19, 47, 49, 21, 747, "19:47:49.021747", "\220\097\019\089\080\102\241\064" ; 23, 28, 6, 739, 112, "23:28:06.739112", "\193\026\103\211\107\160\244\064" ; 7, 9, 8, 205, 617, "07:09:08.205617", "\161\052\212\040\013\037\217\064" ; 5, 18, 39, 798, 546, "05:18:39.798546", "\150\174\096\027\243\171\210\064" ; 15, 29, 5, 932, 40, "15:29:05.932040", "\210\140\069\211\061\056\235\064" ; 6, 37, 20, 310, 776, "06:37:20.310776", "\025\005\193\227\019\072\215\064" ; 1, 14, 1, 596, 82, "01:14:01.596082", "\187\119\212\152\152\089\177\064" ; 11, 58, 44, 243, 253, "11:58:44.243253", "\245\131\186\200\135\014\229\064" ; 19, 33, 14, 433, 195, "19:33:14.433195", "\093\225\093\238\166\047\241\064" ; 21, 52, 16, 100, 165, "21:52:16.100165", "\116\157\070\154\001\057\243\064" ; 21, 42, 33, 743, 278, "21:42:33.743278", "\222\120\119\228\155\020\243\064" ; 19, 2, 49, 99, 566, "19:02:49.099566", "\157\132\210\151\145\189\240\064" ; 20, 23, 45, 272, 392, "20:23:45.272392", "\187\182\183\091\020\237\241\064" ; 23, 32, 51, 56, 641, "23:32:51.056641", "\170\100\000\232\048\178\244\064" ; 22, 48, 30, 551, 738, "22:48:30.551738", "\160\057\235\211\232\011\244\064" ; 3, 48, 49, 382, 761, "03:48:49.382761", "\151\252\079\254\176\208\202\064" ; 16, 2, 43, 728, 168, "16:02:43.728168", "\064\250\038\077\119\052\236\064" ; 10, 3, 5, 375, 842, "10:03:05.375842", "\079\205\229\006\044\171\225\064" ; 5, 39, 7, 750, 836, "05:39:07.750836", "\042\112\178\013\240\222\211\064" ; 15, 31, 30, 620, 367, "15:31:30.620367", "\017\229\011\218\083\074\235\064" ; 21, 34, 44, 579, 580, "21:34:44.579580", "\151\173\245\069\073\247\242\064" ; 5, 11, 9, 581, 907, "05:11:09.581907", "\148\219\246\061\101\059\210\064" ; 10, 20, 2, 317, 308, "10:20:02.317308", "\089\027\099\039\074\042\226\064" ; 21, 27, 49, 389, 501, "21:27:49.389501", "\140\102\101\059\086\221\242\064" ; 4, 45, 7, 724, 591, "04:45:07.724591", "\254\237\178\095\238\180\208\064" ; 16, 39, 39, 373, 406, "16:39:39.373406", "\196\035\241\242\107\073\237\064" ; 8, 51, 46, 595, 693, "08:51:46.595693", "\094\136\213\031\166\040\223\064" ; 9, 47, 26, 907, 258, "09:47:26.907258", "\225\237\065\008\221\053\225\064" ; 22, 33, 31, 144, 30, "22:33:31.144030", "\186\102\242\077\178\211\243\064" ; 14, 56, 32, 996, 430, "14:56:32.996430", "\216\042\193\226\031\068\234\064" ; 12, 7, 7, 545, 441, "12:07:07.545441", "\028\175\064\116\113\077\229\064" ; 12, 40, 36, 922, 966, "12:40:36.922966", "\042\254\239\136\157\072\230\064" ; 12, 42, 53, 21, 763, "12:42:53.021763", "\168\081\072\178\160\089\230\064" ; 22, 30, 27, 515, 128, "22:30:27.515128", "\148\219\246\061\056\200\243\064" ; 15, 53, 30, 148, 909, "15:53:30.148909", "\163\206\220\195\068\239\235\064" ; 23, 56, 21, 892, 35, "23:56:21.892035", "\255\125\198\069\094\010\245\064" ; 1, 12, 22, 74, 744, "01:12:22.074744", "\146\059\108\034\019\246\176\064" ; 8, 43, 2, 645, 910, "08:43:02.645910", "\138\229\150\086\169\165\222\064" ; 21, 37, 56, 904, 657, "21:37:56.904657", "\081\158\121\121\078\003\243\064" ; 23, 24, 6, 417, 377, "23:24:06.417377", "\082\129\147\173\102\145\244\064" ; 23, 38, 33, 148, 241, "23:38:33.148241", "\111\244\049\095\146\199\244\064" ; 13, 2, 15, 863, 848, "13:02:15.863848", "\151\143\164\164\251\234\230\064" ; 11, 49, 31, 559, 654, "11:49:31.559654", "\099\129\175\232\113\201\228\064" ; 7, 18, 34, 621, 69, "07:18:34.621069", "\228\048\152\191\167\178\217\064" ; 21, 5, 56, 513, 37, "21:05:56.513037", "\011\073\102\053\072\139\242\064" ; 6, 49, 57, 814, 594, "06:49:57.814594", "\097\223\078\034\116\005\216\064" ; 21, 15, 15, 459, 515, "21:15:15.459515", "\145\102\044\090\055\174\242\064" ; 5, 54, 17, 930, 468, "05:54:17.930468", "\126\167\201\140\123\194\212\064" ; 10, 5, 42, 364, 332, "10:05:42.364332", "\029\149\155\168\203\190\225\064" ; 0, 43, 39, 845, 998, "00:43:39.845998", "\246\092\166\038\177\119\164\064" ; 22, 58, 19, 905, 830, "22:58:19.905830", "\028\153\071\126\190\048\244\064" ; 23, 27, 22, 829, 188, "23:27:22.829188", "\228\162\090\068\173\157\244\064" ; 22, 1, 15, 411, 476, "22:01:15.411476", "\177\219\103\149\182\090\243\064" ; 13, 45, 30, 359, 70, "13:45:30.359070", "\095\094\128\125\075\047\232\064" ; 18, 30, 58, 875, 552, "18:30:58.875552", "\095\208\066\002\046\070\240\064" ; 15, 11, 59, 52, 509, "15:11:59.052509", "\184\090\039\174\225\183\234\064" ; 5, 32, 27, 180, 353, "05:32:27.180353", "\047\079\231\138\203\122\211\064" ; 15, 20, 53, 564, 91, "15:20:53.564091", "\159\145\008\013\178\250\234\064" ; 5, 1, 35, 261, 392, "05:01:35.261392", "\220\130\165\186\208\171\209\064" ; 19, 14, 51, 688, 269, "19:14:51.688269", "\221\090\038\003\187\234\240\064" ; 20, 3, 22, 465, 391, "20:03:22.465391", "\077\213\061\114\167\160\241\064" ; 2, 44, 34, 432, 318, "02:44:34.432318", "\189\059\050\086\055\073\195\064" ; 15, 2, 4, 332, 994, "15:02:04.332994", "\121\008\227\167\138\109\234\064" ; 4, 50, 17, 63, 828, "04:50:17.063828", "\036\009\194\021\068\002\209\064" ; 23, 19, 14, 315, 616, "23:19:14.315616", "\226\092\195\012\037\127\244\064" ; 8, 26, 37, 647, 152, "08:26:37.647152", "\227\056\240\106\105\175\221\064" ; 19, 13, 32, 39, 857, "19:13:32.039857", "\249\023\065\163\192\229\240\064" ; 4, 58, 27, 102, 90, "04:58:27.102090", "\208\126\164\136\198\124\209\064" ; 20, 13, 0, 914, 292, "20:13:00.914292", "\240\165\240\160\206\196\241\064" ; 14, 28, 18, 364, 829, "14:28:18.364829", "\244\221\173\172\075\112\233\064" ; 1, 54, 24, 297, 289, "01:54:24.297289", "\117\196\033\027\076\208\186\064" ; 22, 1, 37, 447, 964, "22:01:37.447964", "\157\076\220\042\023\092\243\064" ; 9, 22, 18, 522, 75, "09:22:18.522075", "\098\161\214\180\080\121\224\064" ; 5, 32, 54, 268, 695, "05:32:54.268695", "\102\131\076\050\145\129\211\064" ; 15, 47, 48, 808, 138, "15:47:48.808138", "\021\057\068\220\153\196\235\064" ; 21, 27, 25, 379, 878, "21:27:25.379878", "\040\244\250\019\214\219\242\064" ; 6, 20, 44, 34, 522, "06:20:44.034522", "\063\195\155\053\002\079\214\064" ; 16, 55, 53, 566, 876, "16:55:53.566876", "\028\035\217\035\050\195\237\064" ; 0, 7, 24, 625, 34, "00:07:24.625034", "\054\206\166\035\000\202\123\064" ; 4, 57, 25, 135, 740, "04:57:25.135740", "\048\211\246\175\072\109\209\064" ; 9, 2, 33, 681, 509, "09:02:33.681509", "\188\236\215\157\107\202\223\064" ; 23, 32, 17, 288, 647, "23:32:17.288647", "\017\081\076\158\020\176\244\064" ; 19, 41, 49, 103, 976, "19:41:49.103976", "\249\188\226\169\209\079\241\064" ; 20, 1, 2, 6, 960, "20:01:02.006960", "\198\022\130\028\224\151\241\064" ; 11, 11, 55, 682, 104, "11:11:55.682104", "\143\196\203\211\117\175\227\064" ; 11, 9, 57, 318, 812, "11:09:57.318812", "\050\057\181\051\170\160\227\064" ; 15, 33, 5, 821, 75, "15:33:05.821075", "\019\020\063\070\058\086\235\064" ; 22, 55, 28, 207, 467, "22:55:28.207467", "\192\234\200\081\003\038\244\064" ; 15, 56, 36, 590, 369, "15:56:36.590369", "\114\135\077\228\146\006\236\064" ; 16, 11, 17, 832, 950, "16:11:17.832950", "\039\194\134\167\186\116\236\064" ; 18, 13, 56, 119, 941, "18:13:56.119941", "\008\065\071\235\065\006\240\064" ; 15, 48, 32, 810, 612, "15:48:32.810612", "\184\147\136\240\025\202\235\064" ; 7, 52, 2, 577, 717, "07:52:02.577717", "\086\185\080\249\164\168\219\064" ; 18, 52, 5, 883, 488, "18:52:05.883488", "\039\080\196\034\094\149\240\064" ; 22, 28, 10, 774, 763, "22:28:10.774763", "\051\227\109\101\172\191\243\064" ; 13, 58, 15, 677, 176, "13:58:15.677176", "\181\000\109\171\245\142\232\064" ; 0, 42, 26, 531, 691, "00:42:26.531691", "\040\129\205\057\016\229\163\064" ; 7, 5, 51, 929, 630, "07:05:51.929630", "\216\211\014\127\251\243\216\064" ; 21, 43, 30, 145, 766, "21:43:30.145766", "\174\186\014\085\034\024\243\064" ; 12, 9, 46, 677, 708, "12:09:46.677708", "\008\176\200\175\085\097\229\064" ; 15, 17, 18, 994, 9, "15:17:18.994009", "\094\246\235\206\223\223\234\064" ; 10, 13, 12, 286, 140, "10:13:12.286140", "\194\018\015\040\009\247\225\064" ; 11, 43, 3, 512, 129, "11:43:03.512129", "\075\091\092\099\240\152\228\064" ; 14, 27, 5, 579, 11, "14:27:05.579011", "\160\019\066\135\050\103\233\064" ; 13, 43, 56, 798, 310, "13:43:56.798310", "\195\105\193\139\153\035\232\064" ; 1, 34, 33, 332, 260, "01:34:33.332260", "\197\201\253\014\085\041\182\064" ; 3, 53, 14, 927, 689, "03:53:14.927689", "\238\093\131\190\118\085\203\064" ; 14, 5, 14, 934, 569, "14:05:14.934569", "\092\063\253\231\093\195\232\064" ; 5, 5, 29, 957, 39, "05:05:29.957039", "\127\129\032\064\125\230\209\064" ; 16, 5, 7, 49, 384, "16:05:07.049384", "\030\193\141\148\097\070\236\064" ; 17, 5, 10, 366, 575, "17:05:10.366575", "\145\126\251\186\203\008\238\064" ; 17, 20, 55, 208, 512, "17:20:55.208512", "\154\091\033\172\230\126\238\064" ; 4, 5, 6, 978, 489, "04:05:06.978489", "\063\167\032\063\125\185\204\064" ; 10, 49, 1, 643, 656, "10:49:01.643656", "\187\119\212\152\180\003\227\064" ; 20, 10, 40, 347, 239, "20:10:40.347239", "\078\123\074\142\005\188\241\064" ; 21, 29, 44, 812, 880, "21:29:44.812880", "\122\117\142\001\141\228\242\064" ; 5, 44, 5, 1, 135, "05:44:05.001135", "\248\136\152\018\064\041\212\064" ; 13, 15, 0, 443, 497, "13:15:00.443497", "\220\158\032\049\142\074\231\064" ; 15, 57, 24, 650, 620, "15:57:24.650620", "\196\008\225\209\148\012\236\064" ; 9, 56, 56, 274, 828, "09:56:56.274828", "\000\023\100\203\008\125\225\064" ; 2, 16, 59, 783, 937, "02:16:59.783937", "\144\048\012\088\228\013\192\064" ; 22, 56, 55, 188, 110, "22:56:55.188110", "\160\161\127\002\115\043\244\064" ; 7, 3, 11, 135, 724, "07:03:11.135724", "\082\183\179\175\200\203\216\064" ; 21, 18, 14, 990, 938, "21:18:14.990938", "\230\205\225\218\111\185\242\064" ; 14, 42, 14, 493, 402, "14:42:14.493402", "\185\253\242\201\207\216\233\064" ; 23, 40, 49, 535, 0, "23:40:49.535000", "\246\040\092\143\024\208\244\064" ; 7, 10, 48, 884, 90, "07:10:48.884090", "\046\057\238\148\056\062\217\064" ; 9, 1, 38, 491, 759, "09:01:38.491759", "\161\189\250\120\159\188\223\064" ; 20, 42, 37, 181, 14, "20:42:37.181014", "\162\239\110\229\210\051\242\064" ; 8, 55, 24, 981, 786, "08:55:24.981786", "\107\242\148\213\062\095\223\064" ; 7, 52, 36, 4, 909, "07:52:36.004909", "\157\214\109\080\000\177\219\064" ; 7, 51, 29, 683, 833, "07:51:29.683833", "\187\124\235\195\107\160\219\064" ; 22, 31, 25, 124, 134, "22:31:25.124134", "\229\238\115\252\209\203\243\064" ; 17, 14, 47, 644, 343, "17:14:47.644343", "\013\054\117\158\244\080\238\064" ; 14, 27, 34, 166, 805, "14:27:34.166805", "\122\112\119\086\197\106\233\064" ; 6, 45, 54, 178, 550, "06:45:54.178550", "\173\250\092\109\139\200\215\064" ; 22, 28, 19, 412, 648, "22:28:19.412648", "\012\202\052\154\054\192\243\064" ; 9, 15, 46, 951, 195, "09:15:46.951195", "\036\127\048\112\094\072\224\064" ; 3, 3, 0, 233, 718, "03:03:00.233718", "\062\175\120\234\029\114\197\064" ; 22, 12, 56, 843, 867, "22:12:56.843867", "\242\174\122\128\141\134\243\064" ; 13, 44, 53, 467, 82, "13:44:53.467082", "\081\243\085\242\174\042\232\064" ; 23, 31, 13, 841, 320, "23:31:13.841320", "\216\245\011\118\029\172\244\064" ; 14, 2, 54, 403, 357, "14:02:54.403357", "\115\240\076\232\204\177\232\064" ; 6, 37, 2, 306, 466, "06:37:02.306466", "\214\145\035\157\147\067\215\064" ; 4, 21, 28, 271, 485, "04:21:28.271485", "\046\062\005\192\034\164\206\064" ; 12, 43, 25, 134, 95, "12:43:25.134095", "\242\152\129\074\164\093\230\064" ; 23, 58, 32, 956, 833, "23:58:32.956833", "\172\030\048\079\143\018\245\064" ; 16, 20, 28, 2, 554, "16:20:28.002554", "\079\032\236\020\128\185\236\064" ; 15, 20, 55, 620, 463, "15:20:55.620463", "\172\056\213\218\243\250\234\064" ; 20, 29, 16, 783, 498, "20:29:16.783498", "\231\050\053\137\204\001\242\064" ; 17, 16, 1, 78, 174, "17:16:01.078174", "\173\194\102\128\034\090\238\064" ; 23, 31, 58, 585, 609, "23:31:58.585609", "\244\138\167\094\233\174\244\064" ; 1, 53, 51, 695, 249, "01:53:51.695249", "\147\165\214\251\177\175\186\064" ; 18, 50, 28, 911, 811, "18:50:28.911811", "\146\033\199\150\078\143\240\064" ; 19, 12, 31, 101, 465, "19:12:31.101465", "\139\195\153\159\241\225\240\064" ; 11, 45, 34, 766, 408, "11:45:34.766408", "\237\017\106\134\216\171\228\064" ; 20, 24, 19, 896, 233, "20:24:19.896233", "\009\106\248\086\062\239\241\064" ; 6, 26, 43, 998, 321, "06:26:43.998321", "\122\195\125\228\255\168\214\064" ; 2, 2, 44, 963, 347, "02:02:44.963347", "\179\179\232\157\246\196\188\064" ; 12, 30, 59, 941, 41, "12:30:59.941041", "\230\003\002\029\126\000\230\064" ; 8, 20, 14, 15, 949, "08:20:14.015949", "\090\244\078\005\129\079\221\064" ; 19, 55, 45, 841, 913, "19:55:45.841913", "\017\196\121\120\029\132\241\064" ; 1, 29, 2, 525, 150, "01:29:02.525150", "\126\251\058\112\134\222\180\064" ; 18, 34, 24, 805, 483, "18:34:24.805483", "\103\036\066\227\012\083\240\064" ; 15, 4, 27, 31, 407, "15:04:27.031407", "\188\064\073\001\097\127\234\064" ; 8, 45, 54, 180, 442, "08:45:54.180442", "\053\154\092\140\139\208\222\064" ; 17, 21, 42, 674, 557, "17:21:42.674557", "\201\143\248\149\213\132\238\064" ; 9, 19, 9, 86, 601, "09:19:09.086601", "\218\117\111\197\162\097\224\064" ; 23, 45, 16, 237, 129, "23:45:16.237129", "\062\199\071\203\195\224\244\064" ; 11, 8, 30, 948, 432, "11:08:30.948432", "\207\016\142\089\222\149\227\064" ; 7, 26, 30, 972, 902, "07:26:30.972902", "\014\192\006\068\190\041\218\064" ; 18, 23, 38, 286, 852, "18:23:38.286852", "\108\031\242\150\164\042\240\064" ; 11, 27, 44, 42, 686, "11:27:44.042686", "\192\007\175\093\001\038\228\064" ; 21, 50, 13, 331, 478, "21:50:13.331478", "\022\224\187\077\085\049\243\064" ; 6, 27, 32, 278, 679, "06:27:32.278679", "\197\113\224\213\017\181\214\064" ; 9, 14, 34, 113, 954, "09:14:34.113954", "\232\219\130\165\067\063\224\064" ; 20, 46, 32, 730, 87, "20:46:32.730087", "\195\180\111\174\139\066\242\064" ; 14, 59, 51, 850, 707, "14:59:51.850707", "\239\226\253\056\251\092\234\064" ; 23, 19, 3, 398, 52, "23:19:03.398052", "\034\198\107\094\118\126\244\064" ; 12, 2, 30, 450, 632, "12:02:30.450632", "\209\204\147\107\206\042\229\064" ; 19, 39, 56, 419, 463, "19:39:56.419463", "\174\213\030\182\198\072\241\064" ; 4, 55, 42, 356, 125, "04:55:42.356125", "\018\131\192\202\150\083\209\064" ; 7, 31, 8, 664, 763, "07:31:08.664763", "\038\028\122\139\042\111\218\064" ; 0, 30, 27, 637, 585, "00:30:27.637585", "\174\013\021\227\140\142\156\064" ; 10, 59, 44, 63, 305, "10:59:44.063305", "\022\053\152\006\002\084\227\064" ; 5, 31, 41, 764, 454, "05:31:41.764454", "\083\120\208\236\112\111\211\064" ; 10, 5, 44, 47, 108, "10:05:44.047108", "\236\162\232\129\001\191\225\064" ; 8, 38, 34, 105, 232, "08:38:34.105232", "\159\255\030\188\134\098\222\064" ; 4, 47, 19, 226, 649, "04:47:19.226649", "\171\206\106\129\206\213\208\064" ; 21, 23, 52, 926, 48, "21:23:52.926048", "\041\181\023\209\142\206\242\064" ; 19, 28, 8, 672, 139, "19:28:08.672139", "\246\210\020\193\138\028\241\064" ; 7, 54, 5, 73, 121, "07:54:05.073121", "\234\179\003\174\068\199\219\064" ; 10, 11, 40, 335, 901, "10:11:40.335901", "\054\116\179\191\138\235\225\064" ; 2, 19, 48, 439, 402, "02:19:48.439402", "\230\033\083\062\056\098\192\064" ; 10, 32, 3, 538, 60, "10:32:03.538060", "\233\154\201\055\113\132\226\064" ; 5, 18, 1, 508, 935, "05:18:01.508935", "\051\027\100\146\096\162\210\064" ; 10, 41, 42, 860, 218, "10:41:42.860218", "\046\230\231\134\219\204\226\064" ; 9, 13, 55, 223, 267, "09:13:55.223267", "\233\213\000\037\103\058\224\064" ; 15, 11, 38, 21, 908, "15:11:38.021908", "\241\103\120\179\064\181\234\064" ; 17, 53, 16, 25, 251, "17:53:16.025251", "\102\047\219\206\128\113\239\064" ; 0, 22, 39, 207, 999, "00:22:39.207999", "\104\154\176\253\212\060\149\064" ; 9, 24, 10, 496, 491, "09:24:10.496491", "\248\023\065\227\079\135\224\064" ; 3, 8, 1, 850, 204, "03:08:01.850204", "\119\019\124\211\236\008\198\064" ; 9, 28, 38, 326, 846, "09:28:38.326846", "\027\190\133\117\202\168\224\064" ; 2, 22, 14, 102, 548, "02:22:14.102548", "\035\249\074\032\013\171\192\064" ; 16, 26, 54, 273, 541, "16:26:54.273541", "\036\014\217\192\200\233\236\064" ; 8, 1, 29, 842, 405, "08:01:29.842405", "\063\169\246\233\117\054\220\064" ; 20, 1, 20, 768, 178, "20:01:20.768178", "\184\003\117\074\012\153\241\064" ; 0, 7, 46, 217, 208, "00:07:46.217208", "\223\134\024\175\121\035\125\064" ; 2, 28, 52, 531, 748, "02:28:52.531748", "\220\134\081\016\068\114\193\064" ; 8, 39, 34, 556, 278, "08:39:34.556278", "\095\010\015\154\163\113\222\064" ; 15, 25, 46, 284, 865, "15:25:46.284865", "\089\052\157\029\073\031\235\064" ; 10, 27, 33, 881, 119, "10:27:33.881119", "\028\121\032\050\188\098\226\064" ; 23, 36, 23, 550, 496, "23:36:23.550496", "\201\228\212\206\120\191\244\064" ; 19, 23, 27, 678, 858, "19:23:27.678858", "\202\052\154\220\250\010\241\064" ; 6, 42, 18, 569, 218, "06:42:18.569218", "\147\085\017\110\164\146\215\064" ; 8, 12, 49, 228, 861, "08:12:49.228861", "\149\155\168\165\078\224\220\064" ; 11, 30, 5, 2, 320, "11:30:05.002320", "\132\100\001\019\160\055\228\064" ; 20, 39, 32, 49, 427, "20:39:32.049427", "\073\247\115\202\064\040\242\064" ; 7, 3, 11, 686, 213, "07:03:11.686213", "\070\238\233\234\235\203\216\064" ; 7, 34, 47, 368, 739, "07:34:47.368739", "\112\118\107\153\215\165\218\064" ; 7, 57, 53, 979, 742, "07:57:53.979742", "\033\202\023\180\126\000\220\064" ; 7, 52, 38, 504, 362, "07:52:38.504362", "\214\141\119\071\160\177\219\064" ; 21, 41, 2, 199, 126, "21:41:02.199126", "\156\190\158\047\227\014\243\064" ; 9, 44, 5, 402, 387, "09:44:05.402387", "\171\179\090\224\172\028\225\064" ; 4, 5, 27, 875, 497, "04:05:27.875497", "\096\035\073\016\240\195\204\064" ; 23, 18, 16, 616, 316, "23:18:16.616316", "\128\042\110\220\137\123\244\064" ; 6, 32, 11, 800, 756, "06:32:11.800756", "\005\024\150\063\243\250\214\064" ; 13, 20, 55, 482, 11, "13:20:55.482011", "\042\085\162\108\239\118\231\064" ; 15, 17, 45, 416, 274, "15:17:45.416274", "\005\218\029\082\045\227\234\064" ; 15, 24, 45, 723, 496, "15:24:45.723496", "\089\021\225\038\183\023\235\064" ; 11, 35, 9, 655, 106, "11:35:09.655106", "\173\219\160\246\180\093\228\064" ; 9, 1, 21, 744, 342, "09:01:21.744342", "\194\160\076\163\111\184\223\064" ; 22, 3, 32, 229, 314, "22:03:32.229314", "\041\040\069\171\067\099\243\064" ; 15, 29, 29, 892, 940, "15:29:29.892940", "\041\232\246\146\060\059\235\064" ; 11, 27, 59, 671, 118, "11:27:59.671118", "\185\116\204\121\245\039\228\064" ; 3, 40, 59, 920, 664, "03:40:59.920664", "\077\101\081\216\245\229\201\064" ; 10, 7, 46, 929, 841, "10:07:46.929841", "\175\233\065\193\093\206\225\064" ; 7, 14, 47, 275, 956, "07:14:47.275956", "\201\090\067\169\209\121\217\064" ; 0, 28, 49, 934, 45, "00:28:49.934045", "\248\223\074\118\188\007\155\064" ; 13, 2, 31, 93, 796, "13:02:31.093796", "\016\120\096\000\227\236\230\064" ; 16, 8, 38, 724, 160, "16:08:38.724160", "\163\151\081\044\215\096\236\064" ; 15, 35, 42, 525, 59, "15:35:42.525059", "\047\136\072\205\208\105\235\064" ; 15, 43, 33, 127, 150, "15:43:33.127150", "\118\224\156\017\164\164\235\064" ; 10, 43, 19, 348, 76, "10:43:19.348076", "\144\071\112\035\235\216\226\064" ; 7, 13, 37, 658, 560, "07:13:37.658560", "\157\215\216\037\106\104\217\064" ; 4, 2, 47, 569, 678, "04:02:47.569678", "\160\109\053\235\200\115\204\064" ; 0, 18, 39, 368, 33, "00:18:39.368033", "\101\139\164\221\120\125\145\064" ; 22, 24, 4, 518, 495, "22:24:04.518495", "\194\105\193\075\072\176\243\064" ; 11, 50, 2, 803, 429, "11:50:02.803429", "\245\187\176\181\089\205\228\064" ; 8, 44, 7, 636, 852, "08:44:07.636852", "\025\228\046\194\232\181\222\064" ; 18, 34, 52, 664, 821, "18:34:52.664821", "\075\088\027\163\202\084\240\064" ; 0, 40, 1, 933, 747, "00:40:01.933747", "\122\055\022\020\222\195\162\064" ; 19, 49, 38, 838, 502, "19:49:38.838502", "\186\018\129\106\045\109\241\064" ; 16, 35, 45, 765, 899, "16:35:45.765899", "\161\158\062\130\056\044\237\064" ; 10, 25, 1, 646, 579, "10:25:01.646579", "\105\113\198\176\180\079\226\064" ; 14, 3, 1, 915, 837, "14:03:01.915837", "\111\101\137\078\189\178\232\064" ; 17, 8, 25, 39, 9, "17:08:25.039009", "\104\205\143\063\033\033\238\064" ; 16, 59, 37, 947, 609, "16:59:37.947609", "\013\028\208\082\062\223\237\064" ; 7, 58, 57, 55, 680, "07:58:57.055680", "\195\216\066\144\067\016\220\064" ; 2, 35, 50, 506, 40, "02:35:50.506040", "\060\049\235\197\064\067\194\064" ; 12, 43, 53, 420, 414, "12:43:53.420414", "\153\015\008\116\045\097\230\064" ; 22, 50, 53, 483, 962, "22:50:53.483962", "\040\240\078\190\215\020\244\064" ; 15, 27, 53, 237, 640, "15:27:53.237640", "\135\051\191\154\039\047\235\064" ; 0, 5, 2, 140, 908, "00:05:02.140908", "\234\059\191\040\065\226\114\064" ; 1, 35, 32, 300, 539, "01:35:32.300539", "\044\184\031\240\076\100\182\064" ; 18, 38, 47, 6, 101, "18:38:47.006101", "\183\092\253\024\112\099\240\064" ; 11, 2, 31, 590, 939, "11:02:31.590939", "\221\231\248\232\242\104\227\064" ; 3, 5, 26, 881, 129, "03:05:26.881129", "\071\199\213\200\112\187\197\064" ; 10, 29, 13, 240, 90, "10:29:13.240090", "\067\057\209\174\039\111\226\064" ; 4, 19, 33, 252, 130, "04:19:33.252130", "\044\188\203\069\160\106\206\064" ; 2, 15, 25, 201, 172, "02:15:25.201172", "\223\024\002\128\051\189\191\064" ; 18, 41, 48, 315, 680, "18:41:48.315680", "\192\120\006\013\197\110\240\064" ; 0, 37, 37, 222, 525, "00:37:37.222525", "\022\251\203\238\113\162\161\064" ; 11, 23, 49, 189, 840, "11:23:49.189840", "\239\085\043\019\166\008\228\064" ; 3, 55, 28, 764, 626, "03:55:28.764626", "\213\199\067\223\097\152\203\064" ; 14, 13, 59, 882, 800, "14:13:59.882800", "\029\201\229\063\252\004\233\064" ; 14, 23, 39, 680, 888, "14:23:39.680888", "\136\161\213\201\117\077\233\064" ; 19, 33, 56, 227, 527, "19:33:56.227527", "\255\089\243\163\067\050\241\064" ; 18, 9, 8, 438, 165, "18:09:08.438165", "\040\155\114\005\142\232\239\064" ; 5, 41, 54, 586, 355, "05:41:54.586355", "\054\031\215\134\165\008\212\064" ; 23, 30, 23, 6, 183, "23:30:23.006183", "\108\088\083\025\240\168\244\064" ; 19, 24, 45, 267, 738, "19:24:45.267738", "\031\164\167\072\212\015\241\064" ; 8, 27, 57, 362, 454, "08:27:57.362454", "\020\067\114\050\087\195\221\064" ; 8, 43, 34, 621, 424, "08:43:34.621424", "\061\043\105\197\167\173\222\064" ; 0, 2, 13, 537, 412, "00:02:13.537412", "\076\143\166\122\050\177\096\064" ; 13, 3, 47, 731, 450, "13:03:47.731450", "\149\212\009\104\119\246\230\064" ; 4, 19, 47, 585, 553, "04:19:47.585553", "\137\148\102\243\202\113\206\064" ; 20, 47, 21, 380, 209, "20:47:21.380209", "\075\008\086\021\150\069\242\064" ; 13, 29, 56, 903, 299, "13:29:56.903299", "\240\077\211\231\156\186\231\064" ; 20, 23, 29, 290, 916, "20:23:29.290916", "\030\137\151\167\020\236\241\064" ; 3, 28, 9, 949, 935, "03:28:09.949935", "\042\087\120\151\249\100\200\064" ; 10, 9, 36, 535, 314, "10:09:36.535314", "\099\211\074\033\017\220\225\064" ; 1, 27, 54, 382, 413, "01:27:54.382413", "\144\128\209\229\097\154\180\064" ; 18, 16, 4, 802, 490, "18:16:04.802490", "\022\193\255\214\076\014\240\064" ; 15, 20, 17, 815, 919, "15:20:17.815919", "\166\041\002\028\058\246\234\064" ; 13, 59, 2, 505, 648, "13:59:02.505648", "\233\182\068\046\208\148\232\064" ; 23, 57, 5, 567, 168, "23:57:05.567168", "\181\192\030\019\025\013\245\064" ; 4, 55, 0, 262, 557, "04:55:00.262557", "\021\224\187\205\016\073\209\064" ; 18, 59, 28, 651, 353, "18:59:28.651353", "\146\031\241\107\010\177\240\064" ; 8, 20, 4, 305, 866, "08:20:04.305866", "\189\252\078\147\019\077\221\064" ; 9, 8, 44, 130, 440, "09:08:44.130440", "\195\129\144\044\132\019\224\064" ; 6, 45, 5, 534, 501, "06:45:05.534501", "\171\174\067\053\098\188\215\064" ; 17, 14, 39, 876, 639, "17:14:39.876639", "\108\059\109\013\252\079\238\064" ; 21, 48, 56, 556, 282, "21:48:56.556282", "\085\244\135\230\136\044\243\064" ; 16, 52, 37, 212, 591, "16:52:37.212591", "\014\164\139\205\166\170\237\064" ; 19, 14, 38, 742, 137, "19:14:38.742137", "\002\012\203\223\235\233\240\064" ; 20, 49, 8, 769, 279, "20:49:08.769279", "\040\127\247\078\076\076\242\064" ; 3, 37, 1, 691, 766, "03:37:01.691766", "\062\205\201\139\216\110\201\064" ; 8, 43, 36, 691, 293, "08:43:36.691293", "\189\254\036\062\044\174\222\064" ; 18, 17, 42, 901, 580, "18:17:42.901580", "\108\038\223\108\110\020\240\064" ; 7, 58, 21, 256, 311, "07:58:21.256311", "\167\064\102\103\080\007\220\064" ; 8, 57, 6, 468, 100, "08:57:06.468100", "\209\179\089\245\157\120\223\064" ; 1, 0, 32, 698, 838, "01:00:32.698838", "\103\038\024\206\101\097\172\064" ; 11, 6, 30, 757, 843, "11:06:30.757843", "\144\246\063\064\216\134\227\064" ; 23, 41, 48, 294, 289, "23:41:48.294289", "\233\097\104\181\196\211\244\064" ; 14, 42, 58, 887, 294, "14:42:58.887294", "\254\098\182\100\092\222\233\064" ; 15, 45, 56, 640, 210, "15:45:56.640210", "\146\174\153\124\148\182\235\064" ; 18, 3, 23, 121, 836, "18:03:23.121836", "\111\156\020\230\099\189\239\064" ; 5, 5, 40, 925, 897, "05:05:40.925897", "\158\125\229\065\059\233\209\064" ; 15, 18, 20, 720, 295, "15:18:20.720295", "\143\025\168\012\151\231\234\064" ; 13, 2, 11, 705, 693, "13:02:11.705693", "\129\124\009\149\118\234\230\064" ; 11, 4, 2, 835, 199, "11:04:02.835199", "\213\064\243\185\090\116\227\064" ; 18, 33, 7, 42, 131, "18:33:07.042131", "\050\142\145\172\048\078\240\064" ; 19, 9, 7, 192, 294, "19:09:07.192294", "\147\223\162\019\051\213\240\064" ; 17, 42, 9, 129, 272, "17:42:09.129272", "\137\008\255\034\036\030\239\064" ; 6, 27, 1, 595, 215, "06:27:01.595215", "\198\167\000\024\102\173\214\064" ; 10, 15, 1, 889, 681, "10:15:01.889681", "\220\073\068\120\188\004\226\064" ; 2, 2, 19, 101, 781, "02:02:19.101781", "\090\210\081\014\026\171\188\064" ; 0, 22, 58, 766, 313, "00:22:58.766313", "\000\230\090\180\016\139\149\064" ; 14, 9, 9, 245, 615, "14:09:09.245615", "\013\253\019\220\167\224\232\064" ; 10, 40, 5, 109, 735, "10:40:05.109735", "\135\249\242\130\163\192\226\064" ; 5, 10, 19, 748, 266, "05:10:19.748266", "\173\019\151\227\239\046\210\064" ; 6, 26, 2, 226, 179, "06:26:02.226179", "\002\124\183\121\142\158\214\064" ; 22, 20, 11, 384, 144, "22:20:11.384144", "\208\045\116\037\182\161\243\064" ; 23, 41, 24, 879, 369, "23:41:24.879369", "\130\058\229\017\078\210\244\064" ; 10, 31, 17, 72, 739, "10:31:17.072739", "\069\189\224\083\162\126\226\064" ; 2, 8, 41, 151, 918, "02:08:41.151918", "\172\025\025\228\038\041\190\064" ; 17, 41, 50, 365, 227, "17:41:50.365227", "\147\136\240\175\203\027\239\064" ; 17, 22, 9, 875, 160, "17:22:09.875160", "\089\139\079\001\060\136\238\064" ; 8, 20, 53, 828, 198, "08:20:53.828198", "\040\047\050\001\117\089\221\064" ; 20, 53, 17, 22, 876, "20:53:17.022876", "\126\057\179\093\208\091\242\064" ; 19, 54, 45, 522, 502, "19:54:45.522502", "\161\014\043\092\088\128\241\064" ; 9, 52, 20, 144, 911, "09:52:20.144911", "\187\100\028\163\132\090\225\064" ; 8, 30, 47, 660, 168, "08:30:47.660168", "\119\072\049\064\234\237\221\064" ; 23, 46, 17, 832, 60, "23:46:17.832060", "\133\037\030\080\157\228\244\064" ; 16, 51, 8, 287, 684, "16:51:08.287684", "\114\019\181\052\137\159\237\064" ; 3, 29, 44, 542, 603, "03:29:44.542603", "\219\221\003\116\069\148\200\064" ; 13, 45, 6, 460, 5, "13:45:06.460005", "\224\103\092\184\078\044\232\064" ; 14, 35, 57, 921, 386, "14:35:57.921386", "\032\126\254\123\189\169\233\064" ; 2, 8, 25, 500, 928, "02:08:25.500928", "\167\065\209\060\128\025\190\064" ; 23, 2, 45, 540, 151, "23:02:45.540151", "\254\095\117\164\088\065\244\064" ; 12, 48, 32, 266, 587, "12:48:32.266587", "\210\117\225\135\008\132\230\064" ; 22, 47, 4, 549, 702, "22:47:04.549702", "\009\083\148\203\136\006\244\064" ; 21, 11, 23, 445, 801, "21:11:23.445801", "\185\058\000\034\183\159\242\064" ; 7, 4, 15, 945, 820, "07:04:15.945820", "\250\155\080\136\252\219\216\064" ; 9, 40, 23, 515, 555, "09:40:23.515555", "\009\051\109\127\240\000\225\064" ; 13, 51, 18, 471, 915, "13:51:18.471915", "\111\124\237\025\207\090\232\064" ; 0, 44, 55, 423, 172, "00:44:55.423172", "\042\025\000\170\216\014\165\064" ; 19, 22, 14, 617, 302, "19:22:14.617302", "\220\015\120\224\105\006\241\064" ; 14, 23, 20, 357, 416, "14:23:20.357416", "\227\173\243\111\011\075\233\064" ; 21, 25, 50, 452, 337, "21:25:50.452337", "\221\184\197\060\231\213\242\064" ; 8, 59, 43, 200, 542, "08:59:43.200542", "\223\028\174\213\204\159\223\064" ; 2, 32, 50, 352, 544, "02:32:50.352544", "\052\107\041\032\045\233\193\064" ; 2, 6, 12, 931, 587, "02:06:12.931587", "\097\082\124\124\238\148\189\064" ; 8, 2, 36, 696, 65, "08:02:36.696065", "\185\054\084\140\044\071\220\064" ; 3, 23, 32, 962, 154, "03:23:32.962154", "\219\189\220\039\123\218\199\064" ; 15, 49, 45, 849, 301, "15:49:45.849301", "\111\074\121\045\059\211\235\064" ; 6, 54, 7, 166, 903, "06:54:07.166903", "\167\235\137\174\202\067\216\064" ; 22, 41, 27, 924, 575, "22:41:27.924575", "\187\039\015\203\126\241\243\064" ; 12, 17, 20, 64, 279, "12:17:20.064279", "\090\213\146\014\002\154\229\064" ; 6, 21, 55, 449, 759, "06:21:55.449759", "\005\249\217\200\220\096\214\064" ; 14, 41, 0, 834, 592, "14:41:00.834592", "\048\072\250\180\154\207\233\064" ; 9, 45, 39, 696, 591, "09:45:39.696591", "\119\053\121\074\118\040\225\064" ; 14, 31, 50, 269, 796, "14:31:50.269796", "\147\056\043\162\200\138\233\064" ; 6, 39, 33, 781, 139, "06:39:33.781139", "\168\110\046\254\113\105\215\064" ; 8, 21, 16, 866, 470, "08:21:16.866470", "\062\150\062\116\055\095\221\064" ; 23, 55, 3, 159, 669, "23:55:03.159669", "\211\020\001\142\114\005\245\064" ; 5, 30, 33, 803, 236, "05:30:33.803236", "\190\247\055\104\115\094\211\064" ; 9, 20, 33, 838, 678, "09:20:33.838678", "\188\062\115\214\058\108\224\064" ; 5, 40, 4, 314, 694, "05:40:04.314694", "\143\077\242\035\020\237\211\064" ; 11, 10, 53, 945, 334, "11:10:53.945334", "\185\022\045\064\190\167\227\064" ; 3, 43, 56, 773, 153, "03:43:56.773153", "\231\112\173\246\098\062\202\064" ; 11, 12, 5, 595, 250, "11:12:05.595250", "\094\186\073\012\179\176\227\064" ; 12, 13, 26, 312, 721, "12:13:26.312721", "\120\120\207\001\202\124\229\064" ; 20, 53, 45, 539, 982, "20:53:45.539982", "\103\042\196\163\152\093\242\064" ; 20, 16, 40, 310, 671, "20:16:40.310671", "\141\039\130\248\132\210\241\064" ; 3, 30, 1, 531, 215, "03:30:01.531215", "\019\102\218\254\195\156\200\064" ; 15, 16, 33, 846, 731, "15:16:33.846731", "\048\156\107\024\059\218\234\064" ; 23, 27, 53, 766, 88, "23:27:53.766088", "\158\125\229\065\156\159\244\064" ; 13, 30, 30, 792, 713, "13:30:30.792713", "\068\167\231\093\217\190\231\064" ; 13, 6, 33, 95, 476, "13:06:33.095476", "\050\175\035\014\035\011\231\064" ; 5, 30, 24, 448, 972, "05:30:24.448972", "\053\014\245\187\028\092\211\064" ; 4, 33, 56, 338, 400, "04:33:56.338400", "\062\121\088\168\021\013\208\064" ; 23, 43, 7, 471, 734, "23:43:07.471734", "\103\243\056\140\183\216\244\064" ; 11, 27, 12, 269, 807, "11:27:12.269807", "\039\074\066\162\008\034\228\064" ; 15, 22, 21, 708, 30, "15:22:21.708030", "\211\135\046\168\182\005\235\064" ; 2, 12, 42, 696, 715, "02:12:42.696715", "\162\011\234\091\178\026\191\064" ; 15, 37, 7, 179, 609, "15:37:07.179609", "\162\095\091\191\101\116\235\064" ; 0, 55, 17, 805, 321, "00:55:17.805321", "\144\187\008\083\156\235\169\064" ; 10, 13, 28, 679, 466, "10:13:28.679466", "\023\123\047\190\021\249\225\064" ; 12, 32, 59, 492, 226, "12:32:59.492226", "\135\189\080\192\111\015\230\064" ; 9, 59, 47, 391, 669, "09:59:47.391669", "\060\109\141\136\108\146\225\064" ; 7, 32, 51, 216, 652, "07:32:51.216652", "\167\089\160\221\205\136\218\064" ; 12, 59, 6, 946, 109, "12:59:06.946109", "\175\097\134\070\094\211\230\064" ; 9, 55, 42, 173, 300, "09:55:42.173300", "\013\113\172\139\197\115\225\064" ; 3, 55, 54, 852, 848, "03:55:54.852848", "\059\142\031\042\109\165\203\064" ; 7, 30, 53, 967, 416, "07:30:53.967416", "\104\204\036\234\125\107\218\064" ; 11, 21, 58, 850, 621, "11:21:58.850621", "\009\136\073\056\219\250\227\064" ; 20, 56, 50, 416, 516, "20:56:50.416516", "\100\174\012\170\038\105\242\064" ; 5, 38, 51, 42, 364, "05:38:51.042364", "\162\126\023\182\194\218\211\064" ; 21, 10, 11, 525, 286, "21:10:11.525286", "\240\074\146\103\056\155\242\064" ; 9, 30, 18, 662, 445, "09:30:18.662445", "\076\219\191\050\085\181\224\064" ; 12, 51, 47, 51, 625, "12:51:47.051625", "\213\120\233\166\097\156\230\064" ; 19, 12, 37, 724, 400, "19:12:37.724400", "\084\116\036\151\091\226\240\064" ; 23, 58, 11, 951, 130, "23:58:11.951130", "\068\023\212\055\063\017\245\064" ; 23, 9, 3, 412, 703, "23:09:03.412703", "\255\117\110\154\246\088\244\064" ; 23, 56, 17, 133, 340, "23:56:17.133340", "\180\031\041\034\018\010\245\064" ; 3, 53, 47, 579, 676, "03:53:47.579676", "\035\187\210\050\202\101\203\064" ; 0, 29, 52, 439, 428, "00:29:52.439428", "\202\227\105\249\193\001\156\064" ; 21, 11, 58, 161, 407, "21:11:58.161407", "\165\129\031\149\226\161\242\064" ; 4, 48, 22, 591, 952, "04:48:22.591952", "\051\164\138\226\165\229\208\064" ; 2, 47, 0, 935, 291, "02:47:00.935291", "\159\144\157\183\119\146\195\064" ; 7, 31, 31, 611, 253, "07:31:31.611253", "\037\231\196\030\231\116\218\064" ; 4, 54, 52, 452, 886, "04:54:52.452886", "\181\143\021\252\028\071\209\064" ; 9, 4, 57, 920, 553, "09:04:57.920553", "\079\033\087\234\122\238\223\064" ; 15, 44, 12, 192, 453, "15:44:12.192453", "\161\049\147\040\134\169\235\064" ; 14, 7, 57, 723, 639, "14:07:57.723639", "\227\249\012\040\183\215\232\064" ; 0, 39, 42, 279, 892, "00:39:42.279892", "\211\020\001\078\143\156\162\064" ; 23, 35, 39, 166, 489, "23:35:39.166489", "\162\094\240\169\178\188\244\064" ; 8, 44, 42, 950, 827, "08:44:42.950827", "\074\125\089\218\188\190\222\064" ; 2, 21, 12, 214, 558, "02:21:12.214558", "\140\244\162\118\027\140\192\064" ; 0, 21, 16, 712, 766, "00:21:16.712766", "\206\142\084\223\217\242\147\064" ; 5, 29, 58, 224, 398, "05:29:58.224398", "\210\109\137\092\142\085\211\064" ; 16, 47, 43, 478, 156, "16:47:43.478156", "\205\207\013\077\239\133\237\064" ; 12, 36, 22, 299, 323, "12:36:22.299323", "\254\211\013\148\201\040\230\064" ; 8, 5, 33, 957, 865, "08:05:33.957865", "\063\000\169\077\125\115\220\064" ; 1, 40, 4, 447, 733, "01:40:04.447733", "\087\064\161\158\114\116\183\064" ; 5, 24, 16, 214, 267, "05:24:16.214267", "\103\239\140\182\013\000\211\064" ; 6, 37, 2, 883, 110, "06:37:02.883110", "\050\206\223\132\184\067\215\064" ; 5, 56, 14, 630, 485, "05:56:14.630485", "\232\193\221\089\168\223\212\064" ; 0, 35, 34, 743, 526, "00:35:34.743526", "\115\155\112\175\124\173\160\064" ; 22, 0, 26, 943, 734, "22:00:26.943734", "\162\210\136\025\175\087\243\064" ; 6, 33, 41, 343, 165, "06:33:41.343165", "\009\085\106\246\085\017\215\064" ; 0, 0, 6, 886, 982, "00:00:06.886982", "\012\144\104\002\069\140\027\064" ; 4, 54, 57, 359, 59, "04:54:57.359059", "\150\153\210\250\086\072\209\064" ; 15, 52, 34, 662, 730, "15:52:34.662730", "\130\139\021\053\085\232\235\064" ; 19, 4, 7, 543, 105, "19:04:07.543105", "\085\222\142\176\120\194\240\064" ; 4, 46, 29, 858, 659, "04:46:29.858659", "\219\224\068\244\118\201\208\064" ; 20, 21, 30, 644, 192, "20:21:30.644192", "\070\069\156\078\170\228\241\064" ; 23, 18, 28, 814, 259, "23:18:28.814259", "\247\113\052\007\077\124\244\064" ; 15, 44, 13, 58, 616, "15:44:13.058616", "\096\169\046\224\161\169\235\064" ; 1, 15, 57, 881, 233, "01:15:57.881233", "\040\099\124\152\225\205\177\064" ; 20, 16, 22, 594, 916, "20:16:22.594916", "\190\163\198\132\105\209\241\064" ; 0, 20, 2, 219, 881, "00:20:02.219881", "\012\032\124\040\225\200\146\064" ; 2, 48, 45, 184, 250, "02:48:45.184250", "\036\006\129\149\151\198\195\064" ; 4, 3, 29, 312, 753, "04:03:29.312753", "\093\081\074\008\168\136\204\064" ; 13, 38, 33, 0, 335, "13:38:33.000335", "\193\139\190\002\032\251\231\064" ; 22, 48, 20, 462, 827, "22:48:20.462827", "\203\072\189\103\071\011\244\064" ; 5, 29, 1, 438, 384, "05:29:01.438384", "\197\195\123\014\092\071\211\064" ; 22, 1, 53, 913, 604, "22:01:53.913604", "\088\058\031\158\030\093\243\064" ; 22, 41, 50, 546, 167, "22:41:50.546167", "\179\155\025\189\232\242\243\064" ; 1, 28, 47, 101, 211, "01:28:47.101211", "\254\206\246\232\025\207\180\064" ; 11, 6, 17, 785, 848, "11:06:17.785848", "\117\180\170\037\057\133\227\064" ; 12, 30, 38, 270, 105, "12:30:38.270105", "\175\061\179\164\200\253\229\064" ; 23, 3, 5, 368, 555, "23:03:05.368555", "\125\237\153\229\149\066\244\064" ; 4, 49, 16, 746, 269, "04:49:16.746269", "\065\013\223\194\047\243\208\064" ; 11, 16, 53, 827, 716, "11:16:53.827716", "\204\067\166\124\186\212\227\064" ; 14, 58, 4, 784, 74, "14:58:04.784074", "\117\091\034\023\153\079\234\064" ; 5, 23, 0, 949, 173, "05:23:00.949173", "\080\028\064\191\060\237\210\064" ; 2, 39, 9, 325, 43, "02:39:09.325043", "\102\079\002\155\169\166\194\064" ; 10, 19, 46, 958, 740, "10:19:46.958740", "\044\130\255\173\094\040\226\064" ; 17, 27, 24, 525, 221, "17:27:24.525221", "\070\069\156\206\144\175\238\064" ; 17, 27, 21, 835, 974, "17:27:21.835974", "\202\139\076\192\058\175\238\064" ; 14, 18, 31, 996, 753, "14:18:31.996753", "\038\140\102\229\255\038\233\064" ; 3, 9, 59, 301, 513, "03:09:59.301513", "\041\093\250\151\166\067\198\064" ; 12, 32, 28, 624, 364, "12:32:28.624364", "\026\054\202\250\147\011\230\064" ; 18, 16, 3, 856, 205, "18:16:03.856205", "\155\003\004\179\061\014\240\064" ; 18, 47, 40, 112, 47, "18:47:40.112047", "\137\203\241\202\193\132\240\064" ; 9, 47, 53, 34, 952, "09:47:53.034952", "\030\168\083\030\033\057\225\064" ; 11, 7, 20, 223, 592, "11:07:20.223592", "\244\104\170\039\007\141\227\064" ; 0, 34, 17, 583, 681, "00:34:17.583681", "\152\108\060\216\042\019\160\064" ; 5, 56, 11, 26, 515, "05:56:11.026515", "\119\248\107\178\193\222\212\064" ; 23, 50, 1, 450, 441, "23:50:01.450441", "\060\159\001\053\151\242\244\064" ; 15, 2, 5, 30, 790, "15:02:05.030790", "\097\079\059\252\160\109\234\064" ; 11, 5, 37, 988, 927, "11:05:37.988927", "\100\060\074\165\063\128\227\064" ; 8, 31, 56, 802, 239, "08:31:56.802239", "\037\063\226\087\051\255\221\064" ; 0, 51, 58, 946, 325, "00:51:58.946325", "\198\220\181\132\228\093\168\064" ; 3, 15, 5, 706, 487, "03:15:05.706487", "\006\128\042\110\218\220\198\064" ; 11, 39, 39, 853, 452, "11:39:39.853452", "\151\145\122\079\123\127\228\064" ; 19, 2, 56, 477, 375, "19:02:56.477375", "\207\247\083\163\007\190\240\064" ; 11, 48, 37, 874, 850, "11:48:37.874850", "\093\109\197\254\187\194\228\064" ; 23, 58, 18, 699, 3, "23:58:18.699003", "\012\197\029\047\171\017\245\064" ; 7, 56, 9, 727, 203, "07:56:09.727203", "\163\115\126\138\110\230\219\064" ; 17, 59, 2, 818, 588, "17:59:02.818588", "\029\118\223\049\218\156\239\064" ; 11, 36, 51, 725, 822, "11:36:51.725822", "\023\015\239\057\119\106\228\064" ; 12, 0, 52, 427, 587, "12:00:52.427587", "\167\238\202\174\141\030\229\064" ; 15, 51, 12, 795, 393, "15:51:12.795393", "\079\005\220\115\025\222\235\064" ; 13, 17, 46, 832, 568, "13:17:46.832568", "\119\165\101\164\090\095\231\064" ; 9, 54, 9, 611, 44, "09:54:09.611044", "\141\037\172\141\051\104\225\064" ; 19, 21, 17, 543, 628, "19:21:17.543628", "\019\070\179\178\216\002\241\064" ; 12, 31, 7, 655, 78, "12:31:07.655078", "\074\035\102\246\116\001\230\064" ; 16, 43, 28, 572, 35, "16:43:28.572035", "\037\088\028\078\018\102\237\064" ; 5, 32, 4, 808, 555, "05:32:04.808555", "\129\120\093\191\051\117\211\064" ; 11, 26, 16, 21, 197, "11:26:16.021197", "\185\084\165\173\000\027\228\064" ; 12, 11, 33, 281, 869, "12:11:33.281869", "\025\035\018\005\169\110\229\064" ; 8, 45, 52, 97, 764, "08:45:52.097764", "\175\239\195\065\006\208\222\064" ; 8, 17, 33, 978, 741, "08:17:33.978741", "\144\074\177\163\126\039\221\064" ; 19, 15, 28, 832, 50, "19:15:28.832050", "\042\169\019\080\013\237\240\064" ; 23, 52, 32, 81, 860, "23:52:32.081860", "\110\110\076\079\001\252\244\064" ; 10, 9, 14, 212, 312, "10:09:14.212312", "\017\137\066\203\070\217\225\064" ; 23, 44, 40, 765, 794, "23:44:40.765794", "\152\053\177\064\140\222\244\064" ; 12, 2, 1, 946, 292, "12:02:01.946292", "\015\041\006\072\062\039\229\064" ; 23, 0, 22, 378, 152, "23:00:22.378152", "\142\028\233\012\102\056\244\064" ; 16, 15, 8, 167, 114, "16:15:08.167114", "\151\117\255\088\133\145\236\064" ; 3, 38, 5, 272, 616, "03:38:05.272616", "\047\194\020\229\162\142\201\064" ; 2, 53, 12, 717, 556, "02:53:12.717556", "\135\000\224\216\091\076\196\064" ; 4, 21, 38, 163, 196, "04:21:38.163196", "\108\069\155\227\020\169\206\064" ; 8, 29, 6, 615, 105, "08:29:06.615105", "\167\092\225\093\167\212\221\064" ; 9, 3, 29, 825, 503, "09:03:29.825503", "\240\136\010\213\116\216\223\064" ; 12, 37, 19, 33, 193, "12:37:19.033193", "\047\196\234\015\225\047\230\064" ; 3, 22, 16, 970, 9, "03:22:16.970009", "\233\065\065\041\124\180\199\064" ; 18, 56, 6, 196, 973, "18:56:06.196973", "\019\041\205\038\099\164\240\064" ; 17, 16, 57, 420, 5, "17:16:57.420005", "\101\083\174\112\045\097\238\064" ; 15, 35, 38, 758, 899, "15:35:38.758899", "\063\142\230\072\088\105\235\064" ; 1, 25, 30, 935, 924, "01:25:30.935924", "\139\027\183\152\239\010\180\064" ; 9, 41, 15, 905, 502, "09:41:15.905502", "\143\084\223\249\124\007\225\064" ; 9, 30, 47, 945, 592, "09:30:47.945592", "\107\039\074\066\254\184\224\064" ; 4, 3, 2, 876, 0, "04:03:02.876000", "\166\155\196\032\112\123\204\064" ; 18, 59, 0, 674, 264, "18:59:00.674264", "\078\012\201\201\074\175\240\064" ; 8, 50, 24, 109, 960, "08:50:24.109960", "\248\170\149\009\007\020\223\064" ; 13, 29, 46, 564, 300, "13:29:46.564300", "\164\223\190\014\082\185\231\064" ; 15, 34, 0, 598, 812, "15:34:00.598812", "\142\200\119\041\019\093\235\064" ; 1, 33, 40, 732, 104, "01:33:40.732104", "\069\241\042\107\187\244\181\064" ; 17, 7, 31, 263, 878, "17:07:31.263878", "\132\070\176\113\104\026\238\064" ; 3, 39, 46, 146, 524, "03:39:46.146524", "\010\102\076\193\018\193\201\064" ; 10, 31, 9, 909, 246, "10:31:09.909246", "\065\017\139\024\189\125\226\064" ; 11, 51, 55, 720, 212, "11:51:55.720212", "\070\009\250\011\119\219\228\064" ; 20, 15, 22, 361, 240, "20:15:22.361240", "\032\152\163\199\165\205\241\064" ; 15, 3, 47, 802, 684, "15:03:47.802684", "\033\091\150\175\121\122\234\064" ; 10, 43, 27, 205, 237, "10:43:27.205237", "\094\047\077\145\230\217\226\064" ; 19, 12, 43, 640, 272, "19:12:43.640272", "\073\218\141\062\186\226\240\064" ; 7, 56, 30, 820, 987, "07:56:30.820987", "\220\014\013\139\180\235\219\064" ; 2, 39, 53, 606, 406, "02:39:53.606406", "\012\057\182\158\205\188\194\064" ; 3, 19, 42, 465, 325, "03:19:42.465325", "\130\004\197\143\059\103\199\064" ; 19, 7, 50, 325, 707, "19:07:50.325707", "\017\139\024\054\101\208\240\064" ; 1, 35, 12, 260, 898, "01:35:12.260898", "\152\025\054\202\066\080\182\064" ; 17, 0, 38, 181, 667, "17:00:38.181667", "\248\079\055\208\197\230\237\064" ; 9, 28, 7, 561, 546, "09:28:07.561546", "\039\081\047\248\241\164\224\064" ; 2, 14, 18, 771, 975, "02:14:18.771975", "\084\082\039\160\197\122\191\064" ; 22, 43, 29, 560, 252, "22:43:29.560252", "\024\205\202\246\024\249\243\064" ; 7, 31, 5, 222, 642, "07:31:05.222642", "\046\059\196\063\078\110\218\064" ; 18, 15, 32, 796, 886, "18:15:32.796886", "\202\136\011\192\076\012\240\064" ; 21, 19, 28, 24, 809, "21:19:28.024809", "\059\031\158\101\000\190\242\064" ; 7, 32, 1, 632, 177, "07:32:01.632177", "\019\133\150\117\104\124\218\064" ; 5, 38, 13, 27, 320, "05:38:13.027320", "\161\098\156\191\065\209\211\064" ; 8, 22, 22, 761, 306, "08:22:22.761306", "\016\205\060\185\176\111\221\064" ; 22, 48, 40, 604, 398, "22:48:40.604398", "\189\060\157\171\137\012\244\064" ; 16, 24, 32, 395, 730, "16:24:32.395730", "\001\246\209\169\012\216\236\064" ; 1, 13, 33, 389, 944, "01:13:33.389944", "\070\183\094\211\099\061\177\064" ; 8, 54, 37, 585, 265, "08:54:37.585265", "\159\084\251\116\101\083\223\064" ; 19, 32, 1, 331, 473, "19:32:01.331473", "\232\161\182\077\021\043\241\064" ; 8, 40, 29, 939, 161, "08:40:29.939161", "\043\189\054\027\124\127\222\064" ; 8, 15, 7, 401, 761, "08:15:07.401761", "\244\196\115\182\217\002\221\064" ; 7, 37, 33, 909, 595, "07:37:33.909595", "\103\242\205\054\122\207\218\064" ; 11, 47, 32, 444, 531, "11:47:32.444531", "\098\019\153\057\142\186\228\064" ; 18, 24, 4, 70, 103, "18:24:04.070103", "\198\082\036\031\065\044\240\064" ; 7, 8, 12, 502, 853, "07:08:12.502853", "\109\089\190\046\032\023\217\064" ; 10, 10, 8, 765, 326, "10:10:08.765326", "\153\243\140\125\024\224\225\064" ; 18, 32, 49, 771, 352, "18:32:49.771352", "\219\049\117\087\028\077\240\064" ; 1, 25, 18, 299, 714, "01:25:18.299714", "\039\132\014\186\076\254\179\064" ; 16, 12, 33, 246, 555, "16:12:33.246555", "\181\079\199\227\039\126\236\064" ; 18, 53, 40, 588, 464, "18:53:40.588464", "\046\058\089\106\073\155\240\064" ; 22, 26, 8, 702, 137, "22:26:08.702137", "\197\001\244\059\011\184\243\064" ; 1, 54, 10, 860, 511, "01:54:10.860511", "\217\234\114\074\220\194\186\064" ; 4, 0, 56, 137, 472, "04:00:56.137472", "\015\184\174\152\017\060\204\064" ; 23, 52, 25, 123, 199, "23:52:25.123199", "\191\131\159\248\145\251\244\064" ; 3, 22, 4, 861, 838, "03:22:04.861838", "\058\036\181\080\110\174\199\064" ; 3, 27, 31, 71, 846, "03:27:31.071846", "\045\238\063\050\137\081\200\064" ; 8, 34, 23, 782, 125, "08:34:23.782125", "\024\004\086\014\242\035\222\064" ; 9, 29, 24, 679, 395, "09:29:24.679395", "\066\149\154\189\149\174\224\064" ; 4, 11, 31, 866, 733, "04:11:31.866733", "\175\096\027\241\238\121\205\064" ; 4, 11, 30, 756, 410, "04:11:30.756410", "\047\250\010\210\096\121\205\064" ; 17, 22, 3, 566, 370, "17:22:03.566370", "\110\250\179\031\114\135\238\064" ; 3, 56, 41, 425, 516, "03:56:41.425516", "\246\235\078\119\182\188\203\064" ; 19, 33, 38, 883, 21, "19:33:38.883021", "\203\160\218\032\046\049\241\064" ; 14, 10, 48, 511, 584, "14:10:48.511584", "\165\104\229\094\016\237\232\064" ; 4, 58, 2, 105, 136, "04:58:02.105136", "\104\088\140\186\134\118\209\064" ; 4, 46, 51, 19, 495, "04:46:51.019495", "\220\244\103\063\193\206\208\064" ; 21, 26, 57, 112, 93, "21:26:57.112093", "\145\007\034\203\017\218\242\064" ; 14, 58, 37, 228, 956, "14:58:37.228956", "\136\136\155\083\167\083\234\064" ; 11, 13, 58, 298, 7, "11:13:58.298007", "\224\249\069\137\201\190\227\064" ; 14, 14, 27, 310, 272, "14:14:27.310272", "\155\139\191\237\105\008\233\064" ; 4, 55, 21, 359, 414, "04:55:21.359414", "\238\147\163\000\087\078\209\064" ; 8, 43, 30, 756, 622, "08:43:30.756622", "\092\174\126\108\176\172\222\064" ; 1, 53, 36, 295, 611, "01:53:36.295611", "\087\153\041\173\075\160\186\064" ; 5, 30, 15, 955, 299, "05:30:15.955299", "\186\106\158\035\253\089\211\064" ; 4, 34, 55, 178, 991, "04:34:55.178991", "\210\170\150\116\203\027\208\064" ; 15, 15, 18, 795, 589, "15:15:18.795589", "\002\016\119\117\217\208\234\064" ; 9, 30, 40, 735, 447, "09:30:40.735447", "\158\037\200\136\023\184\224\064" ; 12, 41, 59, 0, 698, "12:41:59.000698", "\230\207\183\005\224\082\230\064" ; 20, 46, 6, 675, 215, "20:46:06.675215", "\108\062\174\205\234\064\242\064" ; 16, 50, 9, 308, 904, "16:50:09.308904", "\051\164\138\226\041\152\237\064" ; 4, 18, 48, 578, 65, "04:18:48.578065", "\251\174\008\254\073\084\206\064" ; 9, 53, 33, 169, 727, "09:53:33.169727", "\072\081\103\110\165\099\225\064" ; 12, 26, 20, 818, 897, "12:26:20.818897", "\057\123\103\052\154\221\229\064" ; 8, 37, 46, 395, 814, "08:37:46.395814", "\083\062\004\085\153\086\222\064" ; 10, 39, 32, 128, 785, "10:39:32.128785", "\102\184\001\031\132\188\226\064" ; 8, 33, 27, 671, 453, "08:33:27.671453", "\243\000\022\249\234\021\222\064" ; 6, 53, 58, 649, 857, "06:53:58.649857", "\133\208\065\151\169\065\216\064" ; 10, 46, 24, 322, 777, "10:46:24.322777", "\093\110\048\084\010\240\226\064" ; 8, 47, 6, 32, 407, "08:47:06.032407", "\074\207\244\018\130\226\222\064" ; 19, 50, 22, 214, 412, "19:50:22.214412", "\254\070\059\110\227\111\241\064" ; 15, 53, 47, 289, 168, "15:53:47.289168", "\225\063\221\064\105\241\235\064" ; 10, 35, 40, 590, 158, "10:35:40.590158", "\175\007\147\226\146\159\226\064" ; 9, 10, 0, 690, 377, "09:10:00.690377", "\157\129\145\023\022\029\224\064" ; 13, 31, 14, 8, 770, "13:31:14.008770", "\230\005\216\071\064\196\231\064" ; 16, 44, 52, 607, 831, "16:44:52.607831", "\080\255\089\115\147\112\237\064" ; 12, 41, 55, 749, 128, "12:41:55.749128", "\145\072\219\248\119\082\230\064" ; 14, 26, 13, 780, 719, "14:26:13.780719", "\140\105\166\251\184\096\233\064" ; 13, 5, 30, 339, 390, "13:05:30.339390", "\211\106\072\220\074\003\231\064" ; 0, 48, 44, 564, 664, "00:48:44.564664", "\117\202\163\027\033\217\166\064" ; 6, 12, 32, 748, 785, "06:12:32.748785", "\175\235\023\236\047\212\213\064" ; 13, 10, 49, 567, 646, "13:10:49.567646", "\183\241\039\042\050\043\231\064" ; 11, 36, 45, 728, 534, "11:36:45.728534", "\001\137\038\080\183\105\228\064" ; 5, 42, 37, 849, 262, "05:42:37.849262", "\239\000\079\090\118\019\212\064" ; 0, 57, 23, 722, 17, "00:57:23.722017", "\080\084\054\172\113\231\170\064" ; 16, 54, 52, 572, 792, "16:54:52.572792", "\109\227\079\084\146\187\237\064" ; 9, 44, 57, 869, 474, "09:44:57.869474", "\087\035\187\210\059\035\225\064" ; 11, 20, 14, 480, 762, "11:20:14.480762", "\102\253\102\098\207\237\227\064" ; 16, 58, 29, 722, 415, "16:58:29.722415", "\229\015\006\030\183\214\237\064" ; 18, 10, 22, 221, 312, "18:10:22.221312", "\070\231\252\020\199\241\239\064" ; 15, 24, 37, 974, 769, "15:24:37.974769", "\005\194\078\049\191\022\235\064" ; 1, 11, 1, 49, 20, "01:11:01.049020", "\218\032\147\140\012\165\176\064" ; 4, 50, 1, 48, 329, "04:50:01.048329", "\156\132\210\023\067\254\208\064" ; 2, 38, 59, 589, 754, "02:38:59.589754", "\088\031\015\125\203\161\194\064" ; 11, 49, 45, 23, 73, "11:49:45.023073", "\142\150\003\189\032\203\228\064" ; 23, 50, 46, 334, 665, "23:50:46.334665", "\226\175\201\090\101\245\244\064" ; 9, 13, 15, 560, 358, "09:13:15.560358", "\129\230\115\238\113\053\224\064" ; 20, 43, 5, 370, 761, "20:43:05.370761", "\026\022\163\238\149\053\242\064" ; 20, 58, 13, 765, 951, "20:58:13.765951", "\245\213\085\065\092\110\242\064" ; 0, 44, 59, 208, 101, "00:44:59.208101", "\136\218\054\140\106\022\165\064" ; 22, 53, 52, 42, 236, "22:53:52.042236", "\236\167\255\172\000\032\244\064" ; 3, 39, 0, 755, 401, "03:39:00.755401", "\046\223\250\176\096\170\201\064" ; 15, 37, 18, 91, 39, "15:37:18.091039", "\245\158\202\233\194\117\235\064" ; 4, 36, 50, 222, 999, "04:36:50.222999", "\003\153\157\069\142\056\208\064" ; 22, 26, 9, 699, 855, "22:26:09.699855", "\015\040\155\050\027\184\243\064" ; 4, 23, 14, 967, 52, "04:23:14.967052", "\196\036\092\200\123\217\206\064" ; 4, 10, 0, 411, 859, "04:10:00.411859", "\200\179\203\183\052\076\205\064" ; 21, 12, 52, 134, 386, "21:12:52.134386", "\049\239\113\038\066\165\242\064" ; 13, 44, 33, 299, 405, "13:44:33.299405", "\104\203\185\148\041\040\232\064" ; 17, 41, 22, 349, 697, "17:41:22.349697", "\081\195\183\048\075\024\239\064" ; 8, 28, 47, 964, 284, "08:28:47.964284", "\004\061\212\182\253\207\221\064" ; 14, 32, 14, 640, 305, "14:32:14.640305", "\079\233\096\125\212\141\233\064" ; 17, 33, 55, 233, 759, "17:33:55.233759", "\133\039\244\122\103\224\238\064" ; 15, 12, 35, 762, 488, "15:12:35.762488", "\243\059\077\102\120\188\234\064" ; 1, 56, 46, 168, 787, "01:56:46.168787", "\253\244\159\053\043\094\187\064" ; 21, 45, 34, 225, 985, "21:45:34.225985", "\135\114\162\157\227\031\243\064" ; 9, 33, 31, 504, 169, "09:33:31.504169", "\213\006\039\034\112\205\224\064" ; 15, 13, 24, 267, 978, "15:13:24.267978", "\065\153\070\147\136\194\234\064" ; 0, 18, 17, 629, 855, "00:18:17.629855", "\227\136\181\248\132\038\145\064" ; 23, 19, 45, 470, 269, "23:19:45.470269", "\117\201\056\134\023\129\244\064" ; 1, 26, 1, 764, 284, "01:26:01.764284", "\219\192\029\168\195\041\180\064" ; 1, 2, 50, 106, 441, "01:02:50.106441", "\233\075\111\127\054\116\173\064" ; 15, 35, 25, 141, 566, "15:35:25.141566", "\136\107\181\135\164\103\235\064" ; 1, 6, 6, 27, 931, "01:06:06.027931", "\023\215\248\076\014\252\174\064" ; 11, 58, 59, 585, 564, "11:58:59.585564", "\183\182\240\188\114\016\229\064" ; 13, 27, 1, 610, 815, "13:27:01.610815", "\029\230\203\139\179\164\231\064" ; 21, 55, 12, 416, 36, "21:55:12.416036", "\095\093\021\168\006\068\243\064" ; 12, 22, 50, 35, 596, "12:22:50.035596", "\252\056\154\035\065\195\229\064" ; 1, 43, 59, 995, 586, "01:43:59.995586", "\091\094\185\222\254\095\184\064" ; 8, 21, 41, 432, 357, "08:21:41.432357", "\205\177\188\171\091\101\221\064" ; 7, 58, 18, 267, 84, "07:58:18.267084", "\082\125\231\023\145\006\220\064" ; 18, 54, 2, 854, 121, "18:54:02.854121", "\030\200\122\170\173\156\240\064" ; 8, 4, 7, 215, 92, "08:04:07.215092", "\104\060\017\196\205\093\220\064" ; 5, 22, 50, 361, 845, "05:22:50.361845", "\078\238\119\040\151\234\210\064" ; 21, 39, 26, 465, 525, "21:39:26.465525", "\167\087\202\114\231\008\243\064" ; 4, 32, 31, 590, 641, "04:32:31.590641", "\087\209\031\154\203\239\207\064" ; 10, 6, 49, 52, 424, "10:06:49.052424", "\177\024\117\173\033\199\225\064" ; 16, 10, 35, 350, 940, "16:10:35.350940", "\219\133\230\058\107\111\236\064" ; 5, 4, 41, 455, 86, "05:04:41.455086", "\184\007\033\032\093\218\209\064" ; 15, 11, 22, 851, 244, "15:11:22.851244", "\158\014\100\061\091\179\234\064" ; 19, 12, 0, 669, 230, "19:12:00.669230", "\056\132\042\181\010\224\240\064" ; 10, 1, 57, 687, 139, "10:01:57.687139", "\154\237\010\253\181\162\225\064" ; 0, 18, 0, 203, 408, "00:18:00.203408", "\251\206\047\074\208\224\144\064" ; 14, 52, 39, 372, 227, "14:52:39.372227", "\246\152\072\233\235\038\234\064" ; 5, 11, 53, 310, 179, "05:11:53.310179", "\058\005\249\217\083\070\210\064" ; 12, 44, 57, 519, 725, "12:44:57.519725", "\189\082\150\161\048\105\230\064" ; 18, 26, 36, 739, 91, "18:26:36.739091", "\156\021\081\211\203\053\240\064" ; 21, 27, 37, 900, 924, "21:27:37.900924", "\195\072\047\106\158\220\242\064" ; 4, 51, 36, 352, 835, "04:51:36.352835", "\120\064\217\148\022\022\209\064" ; 0, 8, 19, 265, 871, "00:08:19.265871", "\071\031\243\001\065\052\127\064" ; 8, 3, 13, 910, 301, "08:03:13.910301", "\033\032\095\066\122\080\220\064" ; 10, 34, 52, 632, 617, "10:34:52.632617", "\188\001\102\062\148\153\226\064" ; 21, 2, 58, 286, 318, "21:02:58.286318", "\228\046\194\148\036\128\242\064" ; 21, 49, 53, 725, 220, "21:49:53.725220", "\103\073\128\154\027\048\243\064" ; 18, 12, 46, 362, 107, "18:12:46.362107", "\170\181\048\203\229\001\240\064" ; 14, 2, 46, 934, 267, "14:02:46.934267", "\088\232\131\229\221\176\232\064" ; 19, 24, 2, 473, 150, "19:24:02.473150", "\002\188\005\146\039\013\241\064" ; 3, 43, 36, 872, 256, "03:43:36.872256", "\222\168\021\166\111\052\202\064" ; 5, 53, 41, 419, 2, "05:53:41.419002", "\190\195\237\208\090\185\212\064" ; 13, 31, 2, 92, 26, "13:31:02.092026", "\140\130\224\241\194\194\231\064" ; 11, 31, 51, 126, 664, "11:31:51.126664", "\050\169\161\013\228\068\228\064" ; 4, 14, 51, 328, 739, "04:14:51.328739", "\245\154\030\020\170\221\205\064" ; 2, 10, 1, 375, 64, "02:10:01.375064", "\232\189\049\004\096\121\190\064" ; 12, 1, 55, 947, 578, "12:01:55.947578", "\013\025\143\082\126\038\229\064" ; 21, 42, 25, 202, 915, "21:42:25.202915", "\142\204\035\063\019\020\243\064" ; 10, 51, 1, 865, 337, "10:51:01.865337", "\096\056\215\176\187\018\227\064" ; 20, 23, 28, 450, 919, "20:23:28.450919", "\098\215\246\054\007\236\241\064" ; 2, 23, 31, 683, 257, "02:23:31.683257", "\226\034\247\116\215\209\192\064" ; 8, 16, 14, 213, 603, "08:16:14.213603", "\213\234\171\171\141\019\221\064" ; 6, 57, 33, 488, 151, "06:57:33.488151", "\033\177\221\061\095\119\216\064" ; 14, 10, 34, 273, 451, "14:10:34.273451", "\194\079\028\192\072\235\232\064" ; 5, 51, 44, 959, 963, "05:51:44.959963", "\151\166\008\112\061\156\212\064" ; 7, 2, 24, 888, 637, "07:02:24.888637", "\065\185\109\223\056\192\216\064" ; 4, 26, 2, 152, 652, "04:26:02.152652", "\214\201\025\138\019\045\207\064" ; 8, 25, 1, 954, 66, "08:25:01.954066", "\015\215\106\015\125\151\221\064" ; 15, 7, 27, 806, 623, "15:07:27.806623", "\166\009\219\207\249\149\234\064" ; 16, 35, 35, 798, 596, "16:35:35.798596", "\215\050\025\142\249\042\237\064" ; 8, 8, 16, 965, 676, "08:08:16.965676", "\162\181\162\205\061\156\220\064" ; 5, 51, 32, 715, 532, "05:51:32.715532", "\207\186\070\203\045\153\212\064" ; 16, 15, 9, 929, 560, "16:15:09.929560", "\245\156\244\190\189\145\236\064" ; 3, 48, 28, 869, 366, "03:48:28.869366", "\033\149\098\071\111\198\202\064" ; 20, 20, 23, 484, 743, "20:20:23.484743", "\063\224\129\193\119\224\241\064" ; 16, 3, 37, 403, 488, "16:03:37.403488", "\138\170\095\233\044\059\236\064" ; 7, 39, 59, 435, 933, "07:39:59.435933", "\144\134\083\230\219\243\218\064" ; 18, 14, 20, 270, 301, "18:14:20.270301", "\049\036\039\083\196\007\240\064" ; 6, 25, 55, 577, 668, "06:25:55.577668", "\253\051\131\248\228\156\214\064" ; 4, 37, 40, 510, 257, "04:37:40.510257", "\227\249\012\168\032\069\208\064" ; 1, 41, 26, 603, 613, "01:41:26.603613", "\113\174\097\134\154\198\183\064" ; 23, 7, 43, 886, 692, "23:07:43.886692", "\090\243\227\047\254\083\244\064" ; 8, 29, 7, 682, 209, "08:29:07.682209", "\003\240\079\169\235\212\221\064" ; 6, 43, 5, 69, 312, "06:43:05.069312", "\078\153\155\111\068\158\215\064" ; 11, 20, 55, 642, 949, "11:20:55.642949", "\000\200\009\147\244\242\227\064" ; 23, 24, 32, 934, 667, "23:24:32.934667", "\090\098\101\244\014\147\244\064" ; 2, 24, 30, 334, 972, "02:24:30.334972", "\138\204\092\224\042\239\192\064" ; 17, 33, 8, 902, 195, "17:33:08.902195", "\116\012\200\222\156\218\238\064" ; 7, 30, 26, 109, 668, "07:30:26.109668", "\091\238\204\004\135\100\218\064" ; 18, 10, 54, 524, 857, "18:10:54.524857", "\066\232\160\203\208\245\239\064" ; 5, 23, 24, 542, 979, "05:23:24.542979", "\219\253\042\192\034\243\210\064" ; 10, 7, 30, 3, 60, "10:07:30.003060", "\253\072\017\025\064\204\225\064" ; 5, 1, 40, 267, 474, "05:01:40.267474", "\162\068\075\030\017\173\209\064" ; 15, 12, 42, 109, 524, "15:12:42.109524", "\196\121\056\129\067\189\234\064" ; 7, 47, 2, 31, 553, "07:47:02.031553", "\198\223\246\004\130\093\219\064" ; 21, 3, 36, 948, 277, "21:03:36.948277", "\233\128\036\044\143\130\242\064" ; 9, 0, 48, 284, 639, "09:00:48.284639", "\011\127\134\055\018\176\223\064" ; 16, 23, 55, 156, 629, "16:23:55.156629", "\020\210\026\003\101\211\236\064" ; 18, 5, 13, 746, 774, "18:05:13.746774", "\112\150\146\229\055\203\239\064" ; 15, 59, 30, 13, 863, "15:59:30.013863", "\116\209\144\113\064\028\236\064" ; 12, 15, 11, 117, 829, "12:15:11.117829", "\176\082\065\197\227\137\229\064" ; 7, 43, 48, 326, 209, "07:43:48.326209", "\171\182\155\224\020\045\219\064" ; 5, 12, 13, 681, 808, "05:12:13.681808", "\138\005\190\162\107\075\210\064" ; 13, 34, 48, 872, 434, "13:34:48.872434", "\062\181\250\234\027\223\231\064" ; 16, 8, 52, 686, 535, "16:08:52.686535", "\146\063\024\248\149\098\236\064" ; 20, 51, 23, 946, 820, "20:51:23.946820", "\115\186\044\038\191\084\242\064" ; 22, 58, 38, 867, 50, "22:58:38.867050", "\032\210\111\223\237\049\244\064" ; 0, 26, 56, 972, 829, "00:26:56.972829", "\103\014\073\045\228\067\153\064" ; 20, 20, 21, 322, 578, "20:20:21.322578", "\135\140\071\041\085\224\241\064" ; 8, 0, 47, 89, 528, "08:00:47.089528", "\005\166\211\186\197\043\220\064" ; 8, 47, 43, 900, 895, "08:47:43.900895", "\137\128\067\168\249\235\222\064" ; 10, 33, 29, 586, 632, "10:33:29.586632", "\218\120\176\197\050\143\226\064" ; 10, 42, 56, 178, 838, "10:42:56.178838", "\041\120\010\185\005\214\226\064" ; 0, 54, 10, 38, 100, "00:54:10.038100", "\245\219\215\129\019\100\169\064" ; 11, 48, 26, 64, 376, "11:48:26.064376", "\213\065\094\015\066\193\228\064" ; 14, 56, 40, 722, 936, "14:56:40.722936", "\163\173\074\034\023\069\234\064" ; 1, 27, 56, 620, 485, "01:27:56.620485", "\168\222\026\216\158\156\180\064" ; 16, 31, 5, 130, 208, "16:31:05.130208", "\181\247\169\042\036\009\237\064" ; 12, 23, 39, 494, 755, "12:23:39.494755", "\017\112\008\213\111\201\229\064" ; 8, 23, 12, 637, 387, "08:23:12.637387", "\249\215\242\202\040\124\221\064" ; 13, 26, 10, 10, 49, "13:26:10.010049", "\204\071\082\082\064\158\231\064" ; 18, 45, 25, 45, 47, "18:45:25.045047", "\252\051\131\184\080\124\240\064" ; 5, 58, 33, 415, 28, "05:58:33.415028", "\187\153\209\143\090\002\213\064" ; 0, 57, 4, 706, 752, "00:57:04.706752", "\196\236\101\219\105\193\170\064" ; 10, 55, 30, 849, 970, "10:55:30.849970", "\019\073\244\050\091\052\227\064" ; 22, 48, 51, 977, 40, "22:48:51.977040", "\238\177\244\161\063\013\244\064" ; 9, 5, 8, 842, 428, "09:05:08.842428", "\079\033\087\234\053\241\223\064" ; 17, 50, 14, 387, 969, "17:50:14.387969", "\220\246\061\106\204\090\239\064" ; 11, 12, 17, 619, 547, "11:12:17.619547", "\235\058\084\211\051\178\227\064" ; 12, 30, 14, 293, 876, "12:30:14.293876", "\034\164\110\103\201\250\229\064" ; 11, 44, 0, 97, 987, "11:44:00.097987", "\014\162\181\034\003\160\228\064" ; 7, 31, 46, 173, 73, "07:31:46.173073", "\180\198\160\019\139\120\218\064" ; 8, 43, 36, 532, 335, "08:43:36.532335", "\225\209\198\017\034\174\222\064" ; 0, 25, 17, 163, 579, "00:25:17.163579", "\064\221\064\129\167\180\151\064" ; 3, 23, 31, 597, 893, "03:23:31.597893", "\193\000\194\135\204\217\199\064" ; 8, 27, 35, 944, 697, "08:27:35.944697", "\232\103\234\117\252\189\221\064" ; 10, 29, 24, 816, 810, "10:29:24.816810", "\161\185\078\035\154\112\226\064" ; 9, 47, 59, 629, 677, "09:47:59.629677", "\066\097\080\038\244\057\225\064" ; 13, 46, 58, 464, 42, "13:46:58.464042", "\191\155\110\217\078\058\232\064" ; 18, 57, 42, 277, 399, "18:57:42.277399", "\015\239\057\112\100\170\240\064" ; 10, 59, 14, 162, 519, "10:59:14.162519", "\191\011\091\051\069\080\227\064" ; 12, 10, 57, 781, 296, "12:10:57.781296", "\016\120\096\000\057\106\229\064" ; 15, 43, 28, 90, 741, "15:43:28.090741", "\109\171\089\231\002\164\235\064" ; 16, 13, 42, 475, 249, "16:13:42.475249", "\014\100\061\053\207\134\236\064" ; 11, 39, 37, 202, 918, "11:39:37.202918", "\184\227\077\126\038\127\228\064" ; 15, 43, 17, 729, 46, "15:43:17.729046", "\233\070\088\084\183\162\235\064" ; 23, 36, 0, 901, 383, "23:36:00.901383", "\163\148\016\108\014\190\244\064" ; 20, 36, 10, 207, 937, "20:36:10.207937", "\106\191\181\083\163\027\242\064" ; 17, 8, 39, 171, 370, "17:08:39.171370", "\049\240\220\123\229\034\238\064" ; 19, 9, 25, 218, 681, "19:09:25.218681", "\244\165\183\127\083\214\240\064" ; 2, 37, 29, 46, 63, "02:37:29.046063", "\071\115\100\229\133\116\194\064" ; 13, 6, 38, 633, 612, "13:06:38.633612", "\076\172\140\070\212\011\231\064" ; 10, 44, 31, 479, 908, "10:44:31.479908", "\163\005\104\091\239\225\226\064" ; 1, 1, 7, 378, 340, "01:01:07.378340", "\138\205\199\181\193\166\172\064" ; 12, 6, 31, 818, 72, "12:06:31.818072", "\185\084\165\045\250\072\229\064" ; 6, 1, 47, 491, 724, "06:01:47.491724", "\171\240\103\120\223\050\213\064" ; 10, 36, 31, 792, 849, "10:36:31.792849", "\181\221\004\095\249\165\226\064" ; 6, 45, 47, 518, 541, "06:45:47.518541", "\041\151\198\047\225\198\215\064" ; 3, 8, 25, 866, 61, "03:08:25.866061", "\172\059\022\219\238\020\198\064" ; 15, 40, 13, 409, 59, "15:40:13.409059", "\100\230\002\023\173\139\235\064" ; 15, 9, 33, 82, 497, "15:09:33.082497", "\161\191\208\163\162\165\234\064" ; 10, 57, 23, 915, 698, "10:57:23.915698", "\097\228\101\077\125\066\227\064" ; 23, 32, 20, 346, 880, "23:32:20.346880", "\251\010\210\140\069\176\244\064" ; 17, 28, 45, 944, 586, "17:28:45.944586", "\073\107\012\058\190\185\238\064" ; 9, 46, 0, 33, 546, "09:46:00.033546", "\158\015\207\018\001\043\225\064" ; 14, 51, 7, 913, 4, "14:51:07.913004", "\036\042\084\055\125\027\234\064" ; 1, 32, 16, 759, 116, "01:32:16.759116", "\223\025\109\085\194\160\181\064" ; 4, 8, 37, 572, 841, "04:08:37.572841", "\103\152\218\082\201\034\205\064" ; 7, 32, 19, 148, 531, "07:32:19.148531", "\221\042\136\129\201\128\218\064" ; 8, 9, 34, 452, 813, "08:09:34.452813", "\141\096\227\250\156\175\220\064" ; 4, 24, 3, 330, 236, "04:24:03.330236", "\251\089\044\069\170\241\206\064" ; 6, 20, 6, 94, 688, "06:20:06.094688", "\213\065\094\015\134\069\214\064" ; 10, 14, 50, 478, 605, "10:14:50.478605", "\215\110\187\080\079\003\226\064" ; 0, 23, 27, 989, 165, "00:23:27.989165", "\100\117\171\231\244\255\149\064" ; 15, 43, 35, 717, 480, "15:43:35.717480", "\241\157\152\245\246\164\235\064" ; 12, 52, 58, 431, 462, "12:52:58.431462", "\111\101\137\206\077\165\230\064" ; 11, 55, 16, 872, 216, "11:55:16.872216", "\098\135\049\233\155\244\228\064" ; 19, 36, 30, 929, 705, "19:36:30.929705", "\159\089\018\224\238\059\241\064" ; 1, 1, 21, 858, 860, "01:01:21.858860", "\176\119\127\188\183\195\172\064" ; 5, 27, 7, 236, 82, "05:27:07.236082", "\075\173\247\027\207\042\211\064" ; 0, 9, 48, 646, 932, "00:09:48.646932", "\227\053\175\234\044\101\130\064" ; 4, 35, 33, 619, 632, "04:35:33.619632", "\227\249\012\168\103\037\208\064" ; 10, 54, 11, 96, 141, "10:54:11.096141", "\089\074\150\019\099\042\227\064" ; 16, 27, 16, 196, 212, "16:27:16.196212", "\099\099\094\071\134\236\236\064" ; 10, 57, 53, 149, 701, "10:57:53.149701", "\101\192\089\202\036\070\227\064" ; 13, 28, 20, 28, 779, "13:28:20.028779", "\250\239\193\235\128\174\231\064" ; 15, 43, 10, 261, 963, "15:43:10.261963", "\184\058\000\098\200\161\235\064" ; 3, 53, 10, 596, 407, "03:53:10.596407", "\013\136\016\087\076\083\203\064" ; 7, 25, 19, 754, 227, "07:25:19.754227", "\177\082\065\069\240\023\218\064" ; 21, 35, 18, 856, 726, "21:35:18.856726", "\122\082\038\181\109\249\242\064" ; 23, 1, 58, 746, 408, "23:01:58.746408", "\216\131\073\241\107\062\244\064" ; 14, 20, 3, 362, 558, "14:20:03.362558", "\029\060\019\154\107\050\233\064" ; 5, 36, 10, 415, 557, "05:36:10.415557", "\040\099\124\152\154\178\211\064" ; 2, 22, 51, 129, 98, "02:22:51.129098", "\254\131\072\134\144\189\192\064" ; 12, 20, 2, 586, 786, "12:20:02.586786", "\248\110\243\198\082\174\229\064" ; 0, 38, 14, 570, 447, "00:38:14.570447", "\052\018\161\017\036\237\161\064" ; 3, 10, 42, 100, 20, "03:10:42.100020", "\121\146\116\205\012\089\198\064" ; 8, 47, 22, 669, 924, "08:47:22.669924", "\180\233\008\224\170\230\222\064" ; 18, 41, 37, 229, 479, "18:41:37.229479", "\002\044\242\171\019\110\240\064" ; 2, 24, 40, 96, 999, "02:24:40.096999", "\095\150\118\106\012\244\192\064" ; 2, 5, 50, 162, 909, "02:05:50.162909", "\058\123\103\180\041\126\189\064" ; 4, 25, 56, 496, 437, "04:25:56.496437", "\195\099\063\139\063\042\207\064" ; 7, 25, 9, 801, 221, "07:25:09.801221", "\247\113\052\071\115\021\218\064" ; 22, 7, 16, 440, 360, "22:07:16.440360", "\104\237\182\011\071\113\243\064" ; 11, 11, 31, 10, 780, "11:11:31.010780", "\111\076\079\088\096\172\227\064" ; 2, 53, 50, 845, 513, "02:53:50.845513", "\172\029\197\057\108\095\196\064" ; 21, 1, 39, 615, 604, "21:01:39.615604", "\117\148\131\217\057\123\242\064" ; 16, 3, 4, 906, 153, "16:03:04.906153", "\134\147\052\255\028\055\236\064" ; 14, 57, 12, 498, 392, "14:57:12.498392", "\147\199\211\242\015\073\234\064" ; 2, 11, 48, 913, 492, "02:11:48.913492", "\040\153\156\218\233\228\190\064" ; 3, 3, 0, 65, 418, "03:03:00.065418", "\073\245\157\095\008\114\197\064" ; 10, 26, 48, 171, 504, "10:26:48.171504", "\229\244\245\124\005\093\226\064" ; 4, 13, 48, 433, 605, "04:13:48.433605", "\049\095\094\128\055\190\205\064" ; 18, 29, 26, 460, 127, "18:29:26.460127", "\017\033\174\092\103\064\240\064" ; 17, 28, 24, 136, 576, "17:28:24.136576", "\173\161\212\094\004\183\238\064" ; 17, 26, 14, 713, 863, "17:26:14.713863", "\219\055\247\215\214\166\238\064" ; 2, 12, 5, 522, 918, "02:12:05.522918", "\125\060\244\221\133\245\190\064" ; 1, 16, 12, 987, 754, "01:16:12.987754", "\126\054\114\221\252\220\177\064" ; 21, 44, 13, 757, 238, "21:44:13.757238", "\212\151\165\029\220\026\243\064" ; 7, 25, 31, 629, 679, "07:25:31.629679", "\255\037\169\076\232\026\218\064" ; 13, 24, 27, 479, 267, "13:24:27.479267", "\098\191\039\086\111\145\231\064" ; 0, 35, 2, 165, 594, "00:35:02.165594", "\212\156\188\200\084\108\160\064" ; 13, 56, 49, 92, 134, "13:56:49.092134", "\155\000\195\242\034\132\232\064" ; 0, 39, 40, 193, 254, "00:39:40.193254", "\165\051\048\242\098\152\162\064" ; 2, 35, 50, 229, 998, "02:35:50.229998", "\018\016\147\112\029\067\194\064" ; 13, 34, 1, 129, 740, "13:34:01.129740", "\032\128\212\038\036\217\231\064" ; 20, 33, 14, 823, 646, "20:33:14.823646", "\152\109\167\045\173\016\242\064" ; 6, 30, 34, 636, 144, "06:30:34.636144", "\227\082\149\182\168\226\214\064" ; 8, 17, 9, 241, 943, "08:17:09.241943", "\032\126\254\123\079\033\221\064" ; 3, 36, 18, 991, 666, "03:36:18.991666", "\071\087\233\238\126\089\201\064" ; 17, 35, 39, 126, 911, "17:35:39.126911", "\080\168\167\015\100\237\238\064" ; 13, 34, 27, 244, 631, "13:34:27.244631", "\019\100\004\212\103\220\231\064" ; 14, 15, 31, 170, 473, "14:15:31.170473", "\251\202\131\116\101\016\233\064" ; 2, 18, 50, 594, 575, "02:18:50.594575", "\002\154\008\027\076\069\192\064" ; 19, 31, 41, 427, 608, "19:31:41.427608", "\120\124\123\215\214\041\241\064" ; 19, 54, 41, 677, 395, "19:54:41.677395", "\183\035\156\214\026\128\241\064" ; 7, 16, 55, 25, 859, "07:16:55.025859", "\212\129\172\167\193\153\217\064" ; 3, 50, 41, 164, 957, "03:50:41.164957", "\032\156\079\029\149\008\203\064" ; 0, 21, 27, 399, 281, "00:21:27.399281", "\168\083\030\221\152\029\148\064" ; 22, 49, 16, 125, 482, "22:49:16.125482", "\228\105\249\001\194\014\244\064" ; 8, 42, 10, 299, 701, "08:42:10.299701", "\101\026\077\046\147\152\222\064" ; 14, 48, 22, 102, 148, "14:48:22.102148", "\235\225\203\068\195\006\234\064" ; 5, 54, 8, 85, 649, "05:54:08.085649", "\124\241\069\123\005\192\212\064" ; 16, 43, 59, 180, 470, "16:43:59.180470", "\125\005\105\198\229\105\237\064" ; 9, 28, 38, 577, 112, "09:28:38.577112", "\196\149\179\119\210\168\224\064" ; 0, 5, 56, 111, 589, "00:05:56.111589", "\126\025\140\017\201\065\118\064" ; 18, 31, 54, 690, 77, "18:31:54.690077", "\044\046\142\010\171\073\240\064" ; 15, 45, 20, 114, 700, "15:45:20.114700", "\155\085\159\171\003\178\235\064" ; 2, 53, 56, 483, 187, "02:53:56.483187", "\109\085\018\217\061\098\196\064" ; 19, 24, 23, 365, 911, "19:24:23.365911", "\036\126\197\218\117\014\241\064" ; 23, 47, 31, 207, 193, "23:47:31.207193", "\111\155\169\080\051\233\244\064" ; 6, 44, 4, 887, 222, "06:44:04.887222", "\146\200\062\200\056\173\215\064" ; 22, 13, 32, 619, 631, "22:13:32.619631", "\010\050\002\234\201\136\243\064" ; 3, 15, 26, 407, 130, "03:15:26.407130", "\156\249\213\028\052\231\198\064" ; 0, 8, 54, 707, 484, "00:08:54.707484", "\140\019\095\237\168\181\128\064" ; 16, 47, 34, 196, 122, "16:47:34.196122", "\001\165\161\070\198\132\237\064" ; 3, 22, 4, 975, 851, "03:22:04.975851", "\099\129\175\232\124\174\199\064" ; 22, 28, 2, 801, 987, "22:28:02.801987", "\014\082\240\212\044\191\243\064" ; 9, 30, 37, 134, 871, "09:30:37.134871", "\197\252\220\080\164\183\224\064" ; 16, 52, 37, 125, 641, "16:52:37.125641", "\065\070\064\005\164\170\237\064" ; 20, 30, 22, 230, 712, "20:30:22.230712", "\236\016\255\176\227\005\242\064" ; 7, 6, 50, 892, 478, "07:06:50.892478", "\154\011\092\030\185\002\217\064" ; 7, 39, 9, 315, 797, "07:39:09.315797", "\203\158\004\054\084\231\218\064" ; 14, 29, 13, 441, 650, "14:29:13.441650", "\073\046\255\033\046\119\233\064" ; 22, 41, 34, 239, 330, "22:41:34.239330", "\175\177\075\212\227\241\243\064" ; 6, 37, 19, 458, 774, "06:37:19.458774", "\144\159\141\092\221\071\215\064" ; 0, 38, 15, 65, 136, "00:38:15.065136", "\150\123\129\089\033\238\161\064" ; 12, 39, 43, 211, 892, "12:39:43.211892", "\073\187\209\199\230\065\230\064" ; 0, 49, 3, 333, 595, "00:49:03.333595", "\056\190\246\204\170\254\166\064" ; 10, 15, 36, 126, 644, "10:15:36.126644", "\199\183\119\013\004\009\226\064" ; 23, 30, 7, 953, 58, "23:30:07.953058", "\211\190\185\063\255\167\244\064" ; 12, 36, 22, 499, 85, "12:36:22.499085", "\030\027\129\248\207\040\230\064" ; 16, 11, 18, 861, 35, "16:11:18.861035", "\182\069\153\141\219\116\236\064" ; 11, 3, 43, 607, 518, "11:03:43.607518", "\184\150\201\112\243\113\227\064" ; 1, 11, 23, 823, 352, "01:11:23.823352", "\025\089\050\199\210\187\176\064" ; 14, 3, 21, 581, 57, "14:03:21.581057", "\131\217\004\152\050\181\232\064" ; 10, 23, 12, 852, 801, "10:23:12.852801", "\160\082\037\074\027\066\226\064" ; 6, 34, 1, 630, 371, "06:34:01.630371", "\086\155\255\087\104\022\215\064" ; 3, 2, 53, 684, 757, "03:02:53.684757", "\090\012\030\166\215\110\197\064" ; 0, 31, 28, 215, 934, "00:31:28.215934", "\096\112\205\029\221\128\157\064" ; 13, 33, 16, 859, 474, "13:33:16.859474", "\056\158\207\128\155\211\231\064" ; 17, 2, 2, 822, 222, "17:02:02.822222", "\002\131\164\079\090\241\237\064" ; 15, 31, 0, 834, 41, "15:31:00.834041", "\081\192\118\176\154\070\235\064" ; 7, 15, 17, 740, 595, "07:15:17.740595", "\038\146\232\101\111\129\217\064" ; 21, 29, 8, 196, 616, "21:29:08.196616", "\158\209\086\037\067\226\242\064" ; 7, 59, 54, 964, 834, "07:59:54.964834", "\004\027\215\191\189\030\220\064" ; 22, 16, 13, 19, 976, "22:16:13.019976", "\171\090\210\081\208\146\243\064" ; 8, 22, 45, 588, 513, "08:22:45.588513", "\017\110\050\170\101\117\221\064" ; 10, 23, 29, 200, 76, "10:23:29.200076", "\150\200\005\103\038\068\226\064" ; 0, 37, 2, 676, 76, "00:37:02.676076", "\056\043\162\038\090\093\161\064" ; 17, 9, 12, 636, 219, "17:09:12.636219", "\195\242\231\091\020\039\238\064" ; 2, 41, 13, 850, 59, "02:41:13.850059", "\086\186\187\206\236\228\194\064" ; 3, 24, 34, 678, 364, "03:24:34.678364", "\100\173\161\212\086\249\199\064" ; 18, 24, 1, 488, 469, "18:24:01.488469", "\194\222\196\208\023\044\240\064" ; 19, 21, 48, 60, 236, "19:21:48.060236", "\033\006\186\246\192\004\241\064" ; 17, 23, 6, 385, 424, "17:23:06.385424", "\099\182\100\085\076\143\238\064" ; 22, 46, 45, 67, 212, "22:46:45.067212", "\222\227\076\019\081\005\244\064" ; 13, 53, 7, 980, 101, "13:53:07.980101", "\185\197\252\092\127\104\232\064" ; 13, 31, 54, 940, 143, "13:31:54.940143", "\210\197\166\021\094\201\231\064" ; 13, 35, 42, 224, 820, "13:35:42.224820", "\112\182\185\049\199\229\231\064" ; 11, 1, 34, 628, 217, "11:01:34.628217", "\185\137\090\026\212\097\227\064" ; 4, 46, 3, 699, 233, "04:46:03.699233", "\210\196\059\192\236\194\208\064" ; 7, 48, 23, 190, 433, "07:48:23.190433", "\197\228\013\048\204\113\219\064" ; 21, 4, 52, 345, 764, "21:04:52.345764", "\002\213\063\136\069\135\242\064" ; 2, 20, 23, 704, 251, "02:20:23.704251", "\150\146\229\036\218\115\192\064" ; 11, 14, 56, 413, 303, "11:14:56.413303", "\139\054\199\057\013\198\227\064" ; 19, 9, 41, 316, 211, "19:09:41.316211", "\251\067\051\015\085\215\240\064" ; 14, 7, 26, 652, 953, "14:07:26.652953", "\155\176\253\228\212\211\232\064" ; 10, 27, 50, 288, 117, "10:27:50.288117", "\142\036\065\056\201\100\226\064" ; 18, 38, 44, 182, 198, "18:38:44.182198", "\054\115\072\234\066\099\240\064" ; 9, 0, 47, 423, 816, "09:00:47.423816", "\225\036\205\031\219\175\223\064" ; 23, 35, 23, 196, 993, "23:35:23.196993", "\200\033\226\038\179\187\244\064" ; 8, 43, 7, 286, 475, "08:43:07.286475", "\008\061\155\085\210\166\222\064" ; 5, 29, 21, 272, 870, "05:29:21.272870", "\132\187\179\118\081\076\211\064" ; 21, 38, 35, 711, 188, "21:38:35.711188", "\021\171\006\097\187\005\243\064" ; 6, 39, 41, 744, 761, "06:39:41.744761", "\149\010\042\170\111\107\215\064" ; 11, 14, 1, 464, 709, "11:14:01.464709", "\165\104\229\222\046\191\227\064" ; 15, 0, 44, 188, 265, "15:00:44.188265", "\064\082\068\006\134\099\234\064" ; 16, 39, 53, 537, 380, "16:39:53.537380", "\176\138\055\050\049\075\237\064" ; 15, 17, 41, 223, 865, "15:17:41.223865", "\183\238\230\041\167\226\234\064" ; 22, 40, 1, 414, 635, "22:40:01.414635", "\077\079\088\162\022\236\243\064" ; 8, 32, 14, 26, 34, "08:32:14.026034", "\166\130\138\170\129\003\222\064" ; 20, 42, 57, 181, 425, "20:42:57.181425", "\155\230\029\231\018\053\242\064" ; 20, 51, 55, 914, 185, "20:51:55.914185", "\088\115\128\160\190\086\242\064" ; 6, 8, 26, 239, 62, "06:08:26.239062", "\238\179\202\076\143\150\213\064" ; 13, 45, 39, 144, 691, "13:45:39.144691", "\033\005\079\161\100\048\232\064" ; 23, 45, 56, 420, 801, "23:45:56.420801", "\082\212\153\187\070\227\244\064" ; 22, 27, 13, 253, 19, "22:27:13.253019", "\164\166\093\012\020\188\243\064" ; 10, 33, 53, 797, 682, "10:33:53.797682", "\211\102\156\134\057\146\226\064" ; 19, 51, 41, 519, 52, "19:51:41.519052", "\079\120\009\078\216\116\241\064" ; 11, 49, 1, 586, 203, "11:49:01.586203", "\059\203\044\194\178\197\228\064" ; 9, 40, 53, 225, 827, "09:40:53.225827", "\114\139\249\057\167\004\225\064" ; 15, 58, 48, 234, 400, "15:58:48.234400", "\197\109\052\128\007\023\236\064" ; 18, 4, 59, 502, 566, "18:04:59.502566", "\195\074\005\021\112\201\239\064" ; 14, 13, 10, 918, 220, "14:13:10.918220", "\209\232\014\098\221\254\232\064" ; 20, 43, 10, 236, 12, "20:43:10.236012", "\216\132\180\198\227\053\242\064" ; 4, 37, 9, 893, 966, "04:37:09.893966", "\111\043\189\054\121\061\208\064" ; 20, 49, 52, 930, 502, "20:49:52.930502", "\173\016\086\227\014\079\242\064" ; 8, 0, 45, 728, 214, "08:00:45.728214", "\159\228\014\155\110\043\220\064" ; 19, 10, 59, 33, 831, "19:10:59.033831", "\233\095\146\138\048\220\240\064" ; 2, 24, 10, 82, 72, "02:24:10.082072", "\246\213\085\129\010\229\192\064" ; 7, 43, 32, 891, 631, "07:43:32.891631", "\070\120\123\016\057\041\219\064" ; 21, 45, 30, 38, 254, "21:45:30.038254", "\239\057\176\156\160\031\243\064" ; 9, 34, 37, 510, 567, "09:34:37.510567", "\238\154\144\086\176\213\224\064" ; 4, 23, 50, 183, 116, "04:23:50.183116", "\176\087\088\112\023\235\206\064" ; 6, 32, 15, 262, 570, "06:32:15.262570", "\186\102\242\205\208\251\214\064" ; 18, 28, 54, 725, 545, "18:28:54.725545", "\237\018\213\155\107\062\240\064" ; 15, 57, 1, 985, 205, "15:57:01.985205", "\219\162\204\134\191\009\236\064" ; 5, 6, 40, 300, 152, "05:06:40.300152", "\245\187\176\053\019\248\209\064" ; 0, 10, 31, 733, 275, "00:10:31.733275", "\203\127\072\191\221\189\131\064" ; 5, 41, 7, 98, 902, "05:41:07.098902", "\225\013\105\084\198\252\211\064" ; 5, 26, 8, 572, 447, "05:26:08.572447", "\236\189\248\162\036\028\211\064" ; 0, 16, 13, 948, 919, "00:16:13.948919", "\108\060\216\098\151\111\142\064" ; 7, 33, 48, 846, 380, "07:33:48.846380", "\000\005\023\043\054\151\218\064" ; 18, 17, 39, 280, 800, "18:17:39.280800", "\011\036\040\126\052\020\240\064" ; 15, 56, 38, 346, 6, "15:56:38.346006", "\199\044\123\018\203\006\236\064" ; 14, 14, 44, 317, 33, "14:14:44.317033", "\216\099\034\037\138\010\233\064" ; 14, 1, 9, 813, 953, "14:01:09.813953", "\112\041\231\011\186\164\232\064" ; 20, 31, 50, 16, 720, "20:31:50.016720", "\211\048\124\068\096\011\242\064" ; 8, 34, 55, 214, 50, "08:34:55.214050", "\109\197\254\178\205\043\222\064" ; 16, 37, 34, 119, 47, "16:37:34.119047", "\118\167\059\207\195\057\237\064" ; 4, 1, 36, 61, 431, "04:01:36.061431", "\251\147\248\220\007\080\204\064" ; 15, 46, 58, 910, 48, "15:46:58.910048", "\186\251\028\031\093\190\235\064" ; 15, 35, 50, 263, 630, "15:35:50.263630", "\136\046\168\111\200\106\235\064" ; 6, 10, 20, 245, 270, "06:10:20.245270", "\044\241\128\178\015\179\213\064" ; 6, 42, 9, 899, 271, "06:42:09.899271", "\208\243\167\141\121\144\215\064" ; 19, 11, 1, 814, 530, "19:11:01.814530", "\250\155\080\008\093\220\240\064" ; 5, 5, 18, 414, 567, "05:05:18.414567", "\192\006\068\136\154\227\209\064" ; 22, 24, 6, 885, 51, "22:24:06.885051", "\196\060\043\041\110\176\243\064" ; 4, 20, 5, 725, 907, "04:20:05.725907", "\120\068\133\234\220\122\206\064" ; 5, 56, 52, 443, 775, "05:56:52.443775", "\242\065\207\102\028\233\212\064" ; 20, 39, 33, 660, 171, "20:39:33.660171", "\109\119\015\144\090\040\242\064" ; 20, 38, 50, 200, 158, "20:38:50.200158", "\000\224\216\051\163\037\242\064" ; 2, 19, 22, 669, 824, "02:19:22.669824", "\010\247\202\188\085\085\192\064" ; 10, 27, 58, 638, 538, "10:27:58.638538", "\104\062\231\110\212\101\226\064" ; 0, 13, 11, 954, 888, "00:13:11.954888", "\190\218\081\156\163\191\136\064" ; 11, 10, 57, 69, 5, "11:10:57.069005", "\073\249\073\053\034\168\227\064" ; 12, 4, 2, 973, 272, "12:04:02.973272", "\067\082\011\037\095\054\229\064" ; 9, 22, 42, 567, 650, "09:22:42.567650", "\051\085\048\042\082\124\224\064" ; 1, 25, 36, 129, 539, "01:25:36.129539", "\142\200\119\041\033\016\180\064" ; 15, 3, 23, 493, 710, "15:03:23.493710", "\247\233\120\204\111\119\234\064" ; 6, 40, 8, 903, 507, "06:40:08.903507", "\045\006\015\211\057\114\215\064" ; 8, 58, 21, 878, 626, "08:58:21.878626", "\219\139\104\059\120\139\223\064" ; 10, 3, 27, 472, 531, "10:03:27.472531", "\235\084\249\030\239\173\225\064" ; 22, 28, 55, 542, 101, "22:28:55.542101", "\034\025\114\172\120\194\243\064" ; 6, 34, 59, 424, 420, "06:34:59.424420", "\241\128\178\041\219\036\215\064" ; 19, 55, 9, 281, 181, "19:55:09.281181", "\244\165\183\127\212\129\241\064" ; 6, 7, 28, 604, 135, "06:07:28.604135", "\215\216\037\170\038\136\213\064" ; 0, 47, 58, 175, 695, "00:47:58.175695", "\037\238\177\244\089\124\166\064" ; 4, 32, 26, 299, 38, "04:32:26.299038", "\034\143\224\070\038\237\207\064" ; 15, 13, 6, 871, 680, "15:13:06.871680", "\146\116\205\228\091\192\234\064" ; 16, 41, 53, 198, 591, "16:41:53.198591", "\073\131\219\090\038\090\237\064" ; 17, 26, 8, 209, 880, "17:26:08.209880", "\003\067\086\183\006\166\238\064" ; 19, 43, 32, 805, 208, "19:43:32.805208", "\167\200\033\226\076\086\241\064" ; 21, 20, 31, 45, 11, "21:20:31.045011", "\079\116\093\184\240\193\242\064" ; 7, 5, 22, 222, 892, "07:05:22.222892", "\163\206\220\067\142\236\216\064" ; 11, 30, 37, 682, 617, "11:30:37.682617", "\086\155\255\215\181\059\228\064" ; 9, 48, 21, 762, 85, "09:48:21.762085", "\249\020\000\099\184\060\225\064" ; 22, 32, 12, 622, 880, "22:32:12.622880", "\214\004\081\247\201\206\243\064" ; 19, 54, 36, 219, 690, "19:54:36.219690", "\084\169\217\131\195\127\241\064" ; 19, 36, 6, 938, 992, "19:36:06.938992", "\179\121\028\006\111\058\241\064" ; 23, 29, 15, 58, 803, "23:29:15.058803", "\031\106\219\240\176\164\244\064" ; 2, 47, 18, 438, 899, "02:47:18.438899", "\160\169\215\045\056\155\195\064" ; 12, 2, 31, 689, 291, "12:02:31.689291", "\205\255\171\014\246\042\229\064" ; 20, 11, 20, 664, 951, "20:11:20.664951", "\231\168\163\163\138\190\241\064" ; 3, 58, 34, 10, 499, "03:58:34.010499", "\210\254\007\088\001\245\203\064" ; 3, 11, 48, 210, 221, "03:11:48.210221", "\247\143\133\232\026\122\198\064" ; 0, 23, 18, 227, 176, "00:23:18.227176", "\191\073\211\160\232\216\149\064" ; 17, 58, 7, 862, 735, "17:58:07.862735", "\068\110\134\155\251\149\239\064" ; 2, 4, 16, 264, 428, "02:04:16.264428", "\038\172\141\177\067\032\189\064" ; 19, 38, 0, 609, 636, "19:38:00.609636", "\167\173\017\193\137\065\241\064" ; 22, 43, 33, 976, 106, "22:43:33.976106", "\055\083\033\158\095\249\243\064" ; 14, 7, 16, 595, 70, "14:07:16.595070", "\155\061\208\010\147\210\232\064" ; 22, 38, 36, 399, 689, "22:38:36.399689", "\249\074\032\101\198\230\243\064" ; 12, 9, 45, 839, 45, "12:09:45.839045", "\092\230\116\217\058\097\229\064" ; 11, 1, 57, 581, 547, "11:01:57.581547", "\067\116\008\156\178\100\227\064" ; 17, 52, 43, 449, 671, "17:52:43.449671", "\223\111\180\099\110\109\239\064" ; 15, 22, 52, 138, 528, "15:22:52.138528", "\178\069\210\110\132\009\235\064" ; 22, 59, 22, 71, 969, "22:59:22.071969", "\085\247\200\038\161\052\244\064" ; 14, 46, 41, 28, 116, "14:46:41.028116", "\144\134\083\230\032\250\233\064" ; 12, 15, 40, 436, 430, "12:15:40.436430", "\032\012\060\247\141\141\229\064" ; 1, 31, 8, 824, 616, "01:31:08.824616", "\194\191\008\026\211\092\181\064" ; 8, 28, 23, 641, 396, "08:28:23.641396", "\242\206\161\012\233\201\221\064" ; 16, 13, 43, 240, 320, "16:13:43.240320", "\146\145\179\176\231\134\236\064" ; 21, 11, 24, 850, 19, "21:11:24.850019", "\224\133\173\153\205\159\242\064" ; 2, 6, 12, 175, 462, "02:06:12.175462", "\177\223\019\235\044\148\189\064" ; 10, 0, 7, 178, 952, "10:00:07.178952", "\114\139\249\185\229\148\225\064" ; 16, 5, 33, 495, 465, "16:05:33.495465", "\106\106\217\218\175\073\236\064" ; 22, 59, 10, 908, 523, "22:59:10.908523", "\202\105\079\137\238\051\244\064" ; 6, 0, 8, 957, 617, "06:00:08.957617", "\070\208\152\073\061\026\213\064" ; 7, 6, 55, 303, 264, "07:06:55.303264", "\131\104\173\104\211\003\217\064" ; 1, 0, 36, 376, 873, "01:00:36.376873", "\126\115\127\245\192\104\172\064" ; 20, 53, 30, 210, 501, "20:53:30.210501", "\237\075\054\094\163\092\242\064" ; 2, 51, 13, 358, 116, "02:51:13.358116", "\022\190\190\214\173\016\196\064" ; 2, 49, 7, 769, 635, "02:49:07.769635", "\110\081\102\131\226\209\195\064" ; 19, 43, 5, 938, 332, "19:43:05.938332", "\076\106\104\003\159\084\241\064" ; 6, 48, 18, 271, 245, "06:48:18.271245", "\013\253\019\092\145\236\215\064" ; 11, 45, 52, 133, 122, "11:45:52.133122", "\140\017\137\066\004\174\228\064" ; 23, 7, 44, 804, 416, "23:07:44.804416", "\198\079\227\222\012\084\244\064" ; 7, 43, 59, 111, 229, "07:43:59.111229", "\088\061\096\030\199\047\219\064" ; 6, 27, 30, 795, 361, "06:27:30.795361", "\224\210\049\231\178\180\214\064" ; 13, 40, 0, 542, 724, "13:40:00.542724", "\216\184\254\093\017\006\232\064" ; 16, 40, 21, 684, 233, "16:40:21.684233", "\187\154\060\229\181\078\237\064" ; 22, 35, 18, 841, 198, "22:35:18.841198", "\183\008\140\117\109\218\243\064" ; 22, 54, 18, 322, 499, "22:54:18.322499", "\032\182\244\040\165\033\244\064" ; 8, 23, 54, 773, 881, "08:23:54.773881", "\128\044\068\135\177\134\221\064" ; 13, 29, 29, 239, 629, "13:29:29.239629", "\198\111\010\171\039\183\231\064" ; 22, 58, 38, 505, 577, "22:58:38.505577", "\138\232\215\022\232\049\244\064" ; 12, 29, 4, 940, 982, "12:29:04.940982", "\132\072\134\028\030\242\229\064" ; 17, 40, 37, 171, 292, "17:40:37.171292", "\066\092\057\123\165\018\239\064" ; 10, 36, 46, 680, 3, "10:36:46.680003", "\198\166\149\194\213\167\226\064" ; 12, 29, 49, 845, 664, "12:29:49.845664", "\237\242\173\015\187\247\229\064" ; 17, 41, 21, 70, 238, "17:41:21.070238", "\030\195\099\063\034\024\239\064" ; 4, 2, 42, 945, 461, "04:02:42.945461", "\082\181\221\004\121\113\204\064" ; 22, 55, 58, 786, 143, "22:55:58.786143", "\175\174\010\148\236\039\244\064" ; 22, 27, 37, 707, 921, "22:27:37.707921", "\114\248\164\083\155\189\243\064" ; 17, 45, 57, 644, 986, "17:45:57.644986", "\012\174\185\163\180\058\239\064" ; 1, 54, 11, 935, 675, "01:54:11.935675", "\176\148\101\136\239\195\186\064" ; 23, 21, 58, 823, 809, "23:21:58.823809", "\147\088\082\046\109\137\244\064" ; 15, 12, 48, 661, 124, "15:12:48.661124", "\211\132\237\039\021\190\234\064" ; 19, 23, 17, 562, 411, "19:23:17.562411", "\063\173\162\255\088\010\241\064" ; 2, 6, 2, 919, 394, "02:06:02.919394", "\035\186\103\093\235\138\189\064" ; 11, 59, 9, 344, 881, "11:59:09.344881", "\000\225\067\009\171\017\229\064" ; 17, 55, 20, 104, 496, "17:55:20.104496", "\210\254\007\088\003\129\239\064" ; 0, 51, 37, 712, 852, "00:51:37.712852", "\199\245\239\250\108\051\168\064" ; 19, 13, 32, 742, 630, "19:13:32.742630", "\176\254\207\225\203\229\240\064" ; 0, 6, 55, 776, 655, "00:06:55.776655", "\102\020\203\045\109\252\121\064" ; 4, 24, 2, 225, 59, "04:24:02.225059", "\086\186\187\206\028\241\206\064" ; 8, 30, 22, 183, 186, "08:30:22.183186", "\198\197\081\185\139\231\221\064" ; 9, 19, 33, 466, 333, "09:19:33.466333", "\002\047\051\236\174\100\224\064" ; 12, 47, 3, 948, 42, "12:47:03.948042", "\039\045\092\086\254\120\230\064" ; 17, 45, 11, 502, 982, "17:45:11.502982", "\015\181\109\024\240\052\239\064" ; 19, 1, 1, 123, 709, "19:01:01.123709", "\212\073\182\250\209\182\240\064" ; 13, 55, 30, 862, 704, "13:55:30.862704", "\068\107\069\155\091\122\232\064" ; 5, 43, 10, 546, 641, "05:43:10.546641", "\105\136\042\252\162\027\212\064" ; 12, 55, 17, 931, 171, "12:55:17.931171", "\255\031\039\204\189\182\230\064" ; 20, 8, 48, 520, 483, "20:08:48.520483", "\114\251\229\083\008\181\241\064" ; 18, 8, 51, 536, 419, "18:08:51.536419", "\191\045\088\042\113\230\239\064" ; 14, 59, 4, 578, 869, "14:59:04.578869", "\246\071\024\134\018\087\234\064" ; 11, 42, 12, 323, 206, "11:42:12.323206", "\251\027\180\087\138\146\228\064" ; 20, 42, 18, 24, 655, "20:42:18.024655", "\043\164\252\100\160\050\242\064" ; 4, 38, 44, 425, 21, "04:38:44.425021", "\199\071\139\051\027\085\208\064" ; 23, 13, 15, 701, 286, "23:13:15.701286", "\050\171\119\056\187\104\244\064" ; 3, 48, 21, 779, 676, "03:48:21.779676", "\189\084\108\204\227\194\202\064" ; 20, 39, 19, 287, 739, "20:39:19.287739", "\172\053\148\154\116\039\242\064" ; 18, 35, 37, 375, 613, "18:35:37.375613", "\239\198\130\002\150\087\240\064" ; 1, 43, 1, 453, 914, "01:43:01.453914", "\051\057\181\051\116\037\184\064" ; 10, 35, 58, 629, 52, "10:35:58.629052", "\240\168\049\033\212\161\226\064" ; 2, 49, 38, 202, 263, "02:49:38.202263", "\024\005\193\227\025\225\195\064" ; 23, 52, 49, 162, 702, "23:52:49.162702", "\144\105\109\154\018\253\244\064" ; 4, 46, 51, 418, 380, "04:46:51.418380", "\084\232\188\198\218\206\208\064" ; 0, 13, 16, 915, 738, "00:13:16.915738", "\162\205\113\110\083\231\136\064" ; 0, 51, 6, 526, 557, "00:51:06.526557", "\245\012\225\152\013\245\167\064" ; 23, 34, 44, 602, 147, "23:34:44.602147", "\134\228\100\162\073\185\244\064" ; 16, 50, 37, 68, 699, "16:50:37.068699", "\200\062\200\050\162\155\237\064" ; 17, 47, 46, 435, 525, "17:47:46.435525", "\243\031\210\239\077\072\239\064" ; 20, 3, 10, 738, 179, "20:03:10.738179", "\121\200\148\207\235\159\241\064" ; 13, 10, 10, 56, 26, "13:10:10.056026", "\183\009\247\202\065\038\231\064" ; 4, 51, 46, 935, 560, "04:51:46.935560", "\221\012\055\224\187\024\209\064" ; 21, 54, 4, 306, 856, "21:54:04.306856", "\073\214\225\232\196\063\243\064" ; 19, 43, 48, 807, 934, "19:43:48.807934", "\181\051\076\237\076\087\241\064" ; 12, 49, 31, 771, 781, "12:49:31.771781", "\086\017\110\178\120\139\230\064" ; 0, 18, 38, 365, 225, "00:18:38.365225", "\186\218\138\253\117\121\145\064" ; 11, 35, 37, 423, 321, "11:35:37.423321", "\087\123\216\139\045\097\228\064" ; 0, 19, 52, 324, 184, "00:19:52.324184", "\140\247\227\246\075\161\146\064" ; 14, 49, 4, 599, 925, "14:49:04.599925", "\226\233\149\050\019\012\234\064" ; 8, 20, 39, 80, 224, "08:20:39.080224", "\023\216\099\034\197\085\221\064" ; 19, 30, 55, 625, 275, "19:30:55.625275", "\192\091\032\001\250\038\241\064" ; 17, 38, 37, 652, 880, "17:38:37.652880", "\007\153\100\228\180\003\239\064" ; 15, 7, 32, 294, 57, "15:07:32.294057", "\197\057\234\104\137\150\234\064" ; 17, 16, 49, 954, 86, "17:16:49.954086", "\242\092\223\135\062\096\238\064" ; 14, 59, 47, 437, 384, "14:59:47.437384", "\249\186\012\255\109\092\234\064" ; 9, 55, 24, 544, 956, "09:55:24.544956", "\185\144\071\112\145\113\225\064" ; 11, 31, 25, 698, 403, "11:31:25.698403", "\141\063\081\089\182\065\228\064" ; 18, 48, 39, 193, 942, "18:48:39.193942", "\053\237\098\026\115\136\240\064" ; 14, 55, 0, 855, 108, "14:55:00.855108", "\210\115\011\093\155\056\234\064" ; 9, 7, 37, 12, 727, "09:07:37.012727", "\025\116\066\104\032\011\224\064" ; 0, 33, 12, 547, 392, "00:33:12.547392", "\094\072\135\135\048\034\159\064" ; 20, 18, 18, 79, 795, "20:18:18.079795", "\054\031\215\070\161\216\241\064" ; 23, 17, 36, 689, 336, "23:17:36.689336", "\127\047\133\007\011\121\244\064" ; 16, 24, 31, 398, 803, "16:24:31.398803", "\082\130\254\194\236\215\236\064" ; 3, 55, 14, 824, 679, "03:55:14.824679", "\090\219\020\143\105\145\203\064" ; 14, 4, 20, 469, 11, "14:04:20.469011", "\078\091\035\002\143\188\232\064" ; 3, 18, 28, 438, 721, "03:18:28.438721", "\137\125\002\040\056\066\199\064" ; 5, 17, 0, 660, 933, "05:17:00.660933", "\246\236\185\076\042\147\210\064" ; 0, 55, 17, 653, 442, "00:55:17.653442", "\170\039\243\143\078\235\169\064" ; 0, 41, 9, 40, 861, "00:41:09.040861", "\093\165\187\235\020\074\163\064" ; 12, 33, 11, 312, 904, "12:33:11.312904", "\217\063\079\003\234\016\230\064" ; 6, 35, 50, 708, 853, "06:35:50.708853", "\043\249\216\093\173\049\215\064" ; 16, 34, 4, 373, 528, "16:34:04.373528", "\004\254\240\243\139\031\237\064" ; 1, 55, 39, 863, 375, "01:55:39.863375", "\047\221\036\006\221\027\187\064" ; 17, 57, 25, 16, 456, "17:57:25.016456", "\187\187\206\134\160\144\239\064" ; 5, 16, 20, 861, 433, "05:16:20.861433", "\173\224\183\033\055\137\210\064" ; 19, 26, 1, 679, 252, "19:26:01.679252", "\092\088\055\222\154\020\241\064" ; 3, 27, 1, 10, 129, "03:27:01.010129", "\223\053\232\075\129\066\200\064" ; 18, 10, 6, 572, 21, "18:10:06.572021", "\244\251\254\077\210\239\239\064" ; 21, 42, 13, 557, 499, "21:42:13.557499", "\073\018\132\235\088\019\243\064" ; 22, 13, 52, 405, 448, "22:13:52.405448", "\196\010\183\124\006\138\243\064" ; 8, 59, 41, 587, 128, "08:59:41.587128", "\164\081\129\147\101\159\223\064" ; 13, 56, 38, 67, 181, "13:56:38.067181", "\190\196\088\038\194\130\232\064" ; 1, 47, 55, 796, 191, "01:47:55.796191", "\095\098\044\211\203\075\185\064" ; 12, 5, 50, 908, 924, "12:05:50.908924", "\210\200\231\021\221\067\229\064" ; 1, 53, 10, 397, 735, "01:53:10.397735", "\121\001\246\209\101\134\186\064" ; 7, 22, 7, 852, 117, "07:22:07.852117", "\215\189\021\137\246\231\217\064" ; 18, 34, 4, 961, 302, "18:34:04.961302", "\185\052\126\097\207\081\240\064" ; 4, 27, 46, 256, 371, "04:27:46.256371", "\082\210\195\208\032\097\207\064" ; 1, 22, 52, 92, 0, "01:22:52.092000", "\059\223\079\141\023\108\179\064" ; 21, 50, 28, 839, 744, "21:50:28.839744", "\145\103\151\111\077\050\243\064" ; 21, 4, 53, 968, 907, "21:04:53.968907", "\093\160\164\128\095\135\242\064" ; 17, 19, 41, 653, 467, "17:19:41.653467", "\064\160\051\233\180\117\238\064" ; 1, 6, 3, 170, 509, "01:06:03.170509", "\089\165\244\076\087\246\174\064" ; 2, 53, 16, 151, 895, "02:53:16.151895", "\182\156\075\113\019\078\196\064" ; 5, 45, 23, 782, 561, "05:45:23.782561", "\136\187\122\021\242\060\212\064" ; 4, 12, 46, 578, 747, "04:12:46.578747", "\212\182\097\020\074\159\205\064" ; 12, 50, 43, 404, 971, "12:50:43.404971", "\027\190\133\245\108\148\230\064" ; 14, 25, 3, 73, 361, "14:25:03.073361", "\249\042\249\088\226\087\233\064" ; 10, 54, 41, 613, 929, "10:54:41.613929", "\034\110\078\165\051\046\227\064" ; 12, 35, 58, 996, 387, "12:35:58.996387", "\101\253\102\226\223\037\230\064" ; 23, 10, 55, 707, 737, "23:10:55.707737", "\082\008\228\082\251\095\244\064" ; 23, 23, 33, 740, 851, "23:23:33.740851", "\004\148\134\218\091\143\244\064" ; 16, 8, 24, 807, 859, "16:08:24.807859", "\025\030\251\217\025\095\236\064" ; 8, 5, 8, 171, 31, "08:05:08.171031", "\230\001\044\242\010\109\220\064" ; 15, 50, 27, 546, 431, "15:50:27.546431", "\081\221\092\124\113\216\235\064" ; 14, 55, 23, 847, 110, "14:55:23.847110", "\068\110\134\027\123\059\234\064" ; 13, 20, 49, 749, 682, "13:20:49.749682", "\013\027\101\253\055\118\231\064" ; 11, 23, 57, 90, 370, "11:23:57.090370", "\081\160\079\228\162\009\228\064" ; 12, 15, 40, 406, 603, "12:15:40.406603", "\111\075\228\002\141\141\229\064" ; 19, 42, 47, 11, 142, "19:42:47.011142", "\218\059\163\045\112\083\241\064" ; 23, 15, 54, 966, 806, "23:15:54.966806", "\121\145\009\120\175\114\244\064" ; 1, 27, 8, 687, 836, "01:27:08.687836", "\003\037\005\022\176\108\180\064" ; 23, 28, 35, 906, 247, "23:28:35.906247", "\178\218\252\127\062\162\244\064" ; 19, 15, 47, 413, 20, "19:15:47.413020", "\010\220\186\155\054\238\240\064" ; 2, 41, 44, 491, 434, "02:41:44.491434", "\018\047\079\231\062\244\194\064" ; 2, 58, 48, 166, 700, "02:58:48.166700", "\031\244\108\086\021\244\196\064" ; 11, 51, 45, 179, 510, "11:51:45.179510", "\105\193\139\190\037\218\228\064" ; 4, 12, 12, 987, 228, "04:12:12.987228", "\217\178\124\093\126\142\205\064" ; 23, 56, 51, 718, 526, "23:56:51.718526", "\117\030\021\127\059\012\245\064" ; 5, 14, 43, 313, 423, "05:14:43.313423", "\180\087\031\015\212\112\210\064" ; 16, 30, 34, 678, 853, "16:30:34.678853", "\057\237\041\185\085\005\237\064" ; 8, 18, 23, 805, 976, "08:18:23.805976", "\087\092\028\149\243\051\221\064" ; 13, 52, 53, 322, 522, "13:52:53.322522", "\072\168\025\082\170\102\232\064" ; 16, 56, 54, 274, 68, "16:56:54.274068", "\028\065\042\197\200\202\237\064" ; 12, 59, 58, 849, 967, "12:59:58.849967", "\118\254\237\050\219\217\230\064" ; 7, 27, 16, 970, 397, "07:27:16.970397", "\201\004\252\026\062\053\218\064" ; 2, 47, 19, 513, 55, "02:47:19.513055", "\007\071\201\171\193\155\195\064" ; 21, 44, 55, 684, 946, "21:44:55.684946", "\216\239\137\245\122\029\243\064" ; 2, 9, 25, 720, 758, "02:09:25.720758", "\085\166\152\131\184\085\190\064" ; 3, 38, 23, 358, 302, "03:38:23.358302", "\012\006\215\220\173\151\201\064" ; 4, 21, 18, 494, 783, "04:21:18.494783", "\207\161\012\085\063\159\206\064" ; 4, 15, 56, 598, 339, "04:15:56.598339", "\118\082\095\150\076\254\205\064" ; 3, 19, 14, 79, 482, "03:19:14.079482", "\079\087\119\044\010\089\199\064" ; 15, 0, 56, 673, 79, "15:00:56.673079", "\148\248\220\137\021\101\234\064" ; 14, 45, 23, 746, 396, "14:45:23.746396", "\060\221\121\226\119\240\233\064" ; 22, 33, 35, 904, 184, "22:33:35.904184", "\089\164\137\119\254\211\243\064" ; 6, 28, 0, 965, 882, "06:28:00.965882", "\115\188\002\209\061\188\214\064" ; 18, 41, 46, 889, 855, "18:41:46.889855", "\179\152\216\060\174\110\240\064" ; 2, 41, 30, 969, 357, "02:41:30.969357", "\147\226\227\019\124\237\194\064" ; 7, 15, 49, 610, 594, "07:15:49.610594", "\073\219\248\019\103\137\217\064" ; 18, 32, 43, 887, 317, "18:32:43.887317", "\131\079\115\050\190\076\240\064" ; 18, 57, 11, 46, 946, "18:57:11.046946", "\235\114\074\192\112\168\240\064" ; 23, 52, 44, 759, 977, "23:52:44.759977", "\140\164\221\040\204\252\244\064" ; 7, 12, 34, 13, 842, "07:12:34.013842", "\084\142\201\226\128\088\217\064" ; 3, 27, 34, 104, 189, "03:27:34.104189", "\205\173\016\086\013\083\200\064" ; 17, 45, 59, 414, 758, "17:45:59.414758", "\184\145\178\069\237\058\239\064" ; 6, 18, 19, 935, 870, "06:18:19.935870", "\212\072\075\229\251\042\214\064" ; 21, 33, 50, 266, 181, "21:33:50.266181", "\029\002\071\066\228\243\242\064" ; 20, 17, 23, 397, 425, "20:17:23.397425", "\026\081\218\091\054\213\241\064" ; 16, 23, 43, 657, 240, "16:23:43.657240", "\052\046\028\008\245\209\236\064" ; 5, 31, 1, 545, 769, "05:31:01.545769", "\138\025\225\237\098\101\211\064" ; 21, 47, 17, 970, 937, "21:47:17.970937", "\088\060\245\136\095\038\243\064" ; 6, 28, 52, 140, 539, "06:28:52.140539", "\052\074\151\254\008\201\214\064" ; 17, 52, 59, 335, 429, "17:52:59.335429", "\036\153\213\187\106\111\239\064" ; 5, 15, 7, 786, 970, "05:15:07.786970", "\060\107\183\093\242\118\210\064" ; 4, 25, 59, 474, 164, "04:25:59.474164", "\120\236\103\177\188\043\207\064" ; 23, 33, 57, 795, 715, "23:33:57.795715", "\223\166\063\187\092\182\244\064" ; 15, 4, 44, 28, 339, "15:04:44.028339", "\198\048\039\232\128\129\234\064" ; 1, 8, 25, 508, 442, "01:08:25.508442", "\233\065\065\041\130\009\176\064" ; 2, 17, 15, 690, 407, "02:17:15.690407", "\247\174\065\095\216\021\192\064" ; 2, 38, 4, 143, 664, "02:38:04.143664", "\206\250\148\099\018\134\194\064" ; 7, 42, 6, 605, 321, "07:42:06.605321", "\165\074\148\189\166\019\219\064" ; 22, 2, 2, 952, 492, "22:02:02.952492", "\092\064\104\061\175\093\243\064" ; 23, 0, 21, 571, 192, "23:00:21.571192", "\252\056\154\035\089\056\244\064" ; 13, 35, 59, 535, 472, "13:35:59.535472", "\254\044\150\034\241\231\231\064" ; 5, 53, 20, 868, 998, "05:53:20.868998", "\146\201\169\157\055\180\212\064" ; 5, 36, 2, 765, 304, "05:36:02.765304", "\224\160\189\250\176\176\211\064" ; 16, 2, 20, 909, 824, "16:02:20.909824", "\164\056\071\029\157\049\236\064" ; 12, 27, 24, 455, 981, "12:27:24.455981", "\083\119\101\151\142\229\229\064" ; 4, 10, 27, 253, 619, "04:10:27.253619", "\083\095\150\118\160\089\205\064" ; 10, 48, 56, 8, 904, "10:48:56.008904", "\154\010\241\072\000\003\227\064" ; 3, 58, 51, 773, 720, "03:58:51.773720", "\033\200\065\009\227\253\203\064" ; 16, 24, 57, 596, 80, "16:24:57.596080", "\057\093\022\019\051\219\236\064" ; 16, 38, 53, 372, 574, "16:38:53.372574", "\043\079\032\236\171\067\237\064" ; 3, 30, 16, 949, 312, "03:30:16.949312", "\218\060\014\131\121\164\200\064" ; 11, 44, 26, 905, 453, "11:44:26.905453", "\226\145\120\249\092\163\228\064" ; 4, 33, 5, 867, 389, "04:33:05.867389", "\250\038\077\131\119\000\208\064" ; 8, 22, 12, 411, 881, "08:22:12.411881", "\054\032\066\092\026\109\221\064" ; 9, 8, 49, 600, 256, "09:08:49.600256", "\039\018\076\053\051\020\224\064" ; 23, 36, 19, 341, 550, "23:36:19.341550", "\255\033\253\118\053\191\244\064" ; 13, 50, 27, 784, 691, "13:50:27.784691", "\207\076\048\028\121\084\232\064" ; 16, 5, 52, 756, 781, "16:05:52.756781", "\168\201\140\055\024\076\236\064" ; 17, 17, 31, 36, 680, "17:17:31.036680", "\013\137\123\044\097\101\238\064" ; 12, 31, 46, 581, 461, "12:31:46.581461", "\093\025\084\155\082\006\230\064" ; 21, 58, 48, 248, 715, "21:58:48.248715", "\113\148\188\250\131\081\243\064" ; 7, 1, 12, 893, 526, "07:01:12.893526", "\008\173\135\047\057\174\216\064" ; 18, 20, 36, 815, 69, "18:20:36.815069", "\176\202\133\010\077\031\240\064" ; 17, 33, 19, 169, 79, "17:33:19.169079", "\238\092\024\105\229\219\238\064" ; 6, 38, 40, 994, 970, "06:38:40.994970", "\160\166\150\173\063\092\215\064" ; 6, 37, 44, 485, 631, "06:37:44.485631", "\187\011\148\020\031\078\215\064" ; 2, 34, 9, 186, 860, "02:34:09.186860", "\119\074\007\235\151\016\194\064" ; 13, 36, 59, 597, 971, "13:36:59.597971", "\031\020\148\034\115\239\231\064" ; 22, 38, 40, 88, 944, "22:38:40.088944", "\051\139\080\108\001\231\243\064" ; 0, 20, 47, 796, 862, "00:20:47.796862", "\180\149\151\252\047\127\147\064" ; 9, 58, 34, 355, 957, "09:58:34.355957", "\057\239\255\099\075\137\225\064" ; 11, 4, 56, 587, 906, "11:04:56.587906", "\100\062\032\208\018\123\227\064" ; 13, 4, 47, 111, 400, "13:04:47.111400", "\152\187\150\144\227\253\230\064" ; 11, 2, 59, 655, 902, "11:02:59.655902", "\236\048\038\253\116\108\227\064" ; 16, 7, 16, 395, 118, "16:07:16.395118", "\002\129\206\164\140\086\236\064" ; 9, 16, 48, 666, 716, "09:16:48.666716", "\247\202\188\085\021\080\224\064" ; 23, 20, 28, 531, 978, "23:20:28.531978", "\003\093\251\130\200\131\244\064" ; 23, 50, 5, 455, 641, "23:50:05.455641", "\156\055\078\074\215\242\244\064" ; 23, 27, 27, 154, 778, "23:27:27.154778", "\002\127\248\121\242\157\244\064" ; 6, 46, 16, 786, 771, "06:46:16.786771", "\156\192\116\090\050\206\215\064" ; 15, 22, 51, 553, 520, "15:22:51.553520", "\054\147\111\182\113\009\235\064" ; 8, 22, 56, 364, 953, "08:22:56.364953", "\229\211\099\091\023\120\221\064" ; 20, 25, 30, 186, 875, "20:25:30.186875", "\215\163\112\253\162\243\241\064" ; 21, 15, 40, 769, 524, "21:15:40.769524", "\216\101\248\079\204\175\242\064" ; 1, 56, 45, 222, 498, "01:56:45.222498", "\109\001\161\245\056\093\187\064" ; 21, 41, 15, 140, 440, "21:41:15.140440", "\113\003\062\063\178\015\243\064" ; 5, 47, 18, 126, 569, "05:47:18.126569", "\236\220\180\025\136\089\212\064" ; 0, 26, 58, 500, 113, "00:26:58.500113", "\056\077\159\029\000\074\153\064" ; 19, 3, 7, 40, 621, "19:03:07.040621", "\168\052\098\166\176\190\240\064" ; 8, 12, 52, 961, 855, "08:12:52.961855", "\031\070\008\143\061\225\220\064" ; 10, 4, 46, 756, 201, "10:04:46.756201", "\135\112\204\050\216\183\225\064" ; 17, 23, 36, 238, 905, "17:23:36.238905", "\059\025\028\165\007\147\238\064" ; 5, 11, 45, 253, 430, "05:11:45.253430", "\117\118\050\056\080\068\210\064" ; 5, 7, 13, 367, 546, "05:07:13.367546", "\113\168\223\133\087\000\210\064" ; 21, 17, 31, 373, 206, "21:17:31.373206", "\203\218\166\248\181\182\242\064" ; 4, 51, 17, 87, 641, "04:51:17.087641", "\050\255\232\155\069\017\209\064" ; 9, 30, 37, 977, 348, "09:30:37.977348", "\026\080\111\070\191\183\224\064" ; 16, 45, 35, 132, 436, "16:45:35.132436", "\026\108\234\060\228\117\237\064" ; 4, 24, 13, 689, 503, "04:24:13.689503", "\191\097\162\065\216\246\206\064" ; 7, 12, 44, 763, 94, "07:12:44.763094", "\113\055\136\214\048\091\217\064" ; 7, 24, 27, 294, 179, "07:24:27.294179", "\011\040\212\211\210\010\218\064" ; 2, 33, 25, 28, 338, "02:33:25.028338", "\158\095\148\160\131\250\193\064" ; 19, 16, 56, 122, 754, "19:16:56.122754", "\247\229\204\246\129\242\240\064" ; 17, 43, 54, 44, 439, "17:43:54.044439", "\118\086\011\108\065\043\239\064" ; 11, 34, 46, 766, 273, "11:34:46.766273", "\090\244\078\133\216\090\228\064" ; 16, 11, 56, 299, 150, "16:11:56.299150", "\083\005\163\146\137\121\236\064" ; 19, 51, 55, 382, 995, "19:51:55.382995", "\120\093\191\032\182\117\241\064" ; 5, 28, 22, 94, 445, "05:28:22.094445", "\146\010\099\011\134\061\211\064" ; 16, 36, 49, 544, 626, "16:36:49.544626", "\082\129\147\109\049\052\237\064" ; 12, 25, 39, 274, 738, "12:25:39.274738", "\159\088\167\202\104\216\229\064" ; 16, 5, 38, 728, 950, "16:05:38.728950", "\078\243\142\083\087\074\236\064" ; 17, 37, 55, 884, 475, "17:37:55.884475", "\228\131\158\077\124\254\238\064" ; 5, 46, 31, 486, 987, "05:46:31.486987", "\165\133\203\042\223\077\212\064" ; 6, 12, 3, 777, 894, "06:12:03.777894", "\112\234\003\201\241\204\213\064" ; 1, 38, 32, 600, 41, "01:38:32.600041", "\067\119\073\156\153\024\183\064" ; 14, 31, 51, 438, 965, "14:31:51.438965", "\227\083\000\012\238\138\233\064" ; 1, 45, 37, 125, 936, "01:45:37.125936", "\100\121\087\061\032\193\184\064" ; 16, 16, 10, 537, 650, "16:16:10.537650", "\214\197\109\052\081\153\236\064" ; 10, 8, 3, 243, 415, "10:08:03.243415", "\012\065\014\202\103\208\225\064" ; 15, 41, 54, 119, 781, "15:41:54.119781", "\182\246\062\213\067\152\235\064" ; 17, 3, 11, 747, 537, "17:03:11.747537", "\242\182\210\235\247\249\237\064" ; 14, 36, 33, 827, 717, "14:36:33.827717", "\171\092\168\124\058\174\233\064" ; 16, 41, 21, 953, 969, "16:41:21.953969", "\013\255\233\134\062\086\237\064" ; 3, 25, 14, 725, 621, "03:25:14.725621", "\037\032\038\225\092\013\200\064" ; 9, 49, 0, 492, 527, "09:49:00.492527", "\172\251\199\194\143\065\225\064" ; 17, 19, 39, 893, 512, "17:19:39.893512", "\082\122\166\151\124\117\238\064" ; 9, 6, 54, 550, 68, "09:06:54.550068", "\211\052\040\154\209\005\224\064" ; 15, 21, 23, 56, 43, "15:21:23.056043", "\133\176\026\203\097\254\234\064" ; 2, 59, 3, 184, 45, "02:59:03.184045", "\255\091\201\142\151\251\196\064" ; 9, 29, 27, 285, 169, "09:29:27.285169", "\027\189\026\032\233\174\224\064" ; 6, 25, 9, 624, 105, "06:25:09.624105", "\017\025\086\241\103\145\214\064" ; 12, 0, 47, 944, 741, "12:00:47.944741", "\071\122\081\059\254\029\229\064" ; 20, 29, 23, 55, 144, "20:29:23.055144", "\201\172\222\225\048\002\242\064" ; 6, 14, 16, 587, 35, "06:14:16.587035", "\167\063\251\145\037\238\213\064" ; 4, 55, 44, 680, 510, "04:55:44.680510", "\167\208\121\141\043\084\209\064" ; 0, 35, 4, 138, 916, "00:35:04.138916", "\200\121\255\031\071\112\160\064" ; 14, 29, 40, 85, 392, "14:29:40.085392", "\235\000\136\187\130\122\233\064" ; 13, 55, 23, 75, 69, "13:55:23.075069", "\126\026\247\102\098\121\232\064" ; 22, 17, 33, 436, 710, "22:17:33.436710", "\253\159\195\252\214\151\243\064" ; 13, 6, 45, 771, 321, "13:06:45.771321", "\183\096\169\174\184\012\231\064" ; 1, 0, 27, 367, 548, "01:00:27.367548", "\108\095\064\047\188\086\172\064" ; 14, 49, 18, 148, 565, "14:49:18.148565", "\011\099\011\193\196\013\234\064" ; 20, 10, 57, 568, 102, "20:10:57.568102", "\109\031\242\022\025\189\241\064" ; 3, 31, 51, 334, 997, "03:31:51.334997", "\161\131\046\225\170\211\200\064" ; 10, 43, 31, 405, 686, "10:43:31.405686", "\206\052\097\251\108\218\226\064" ; 21, 13, 41, 855, 253, "21:13:41.855253", "\013\197\029\175\093\168\242\064" ; 10, 34, 5, 100, 399, "10:34:05.100399", "\177\246\119\054\163\147\226\064" ; 22, 23, 49, 377, 290, "22:23:49.377290", "\049\061\097\009\086\175\243\064" ; 2, 48, 41, 604, 770, "02:48:41.604770", "\205\117\026\105\205\196\195\064" ; 12, 47, 7, 277, 561, "12:47:07.277561", "\053\155\199\225\104\121\230\064" ; 16, 24, 15, 794, 634, "16:24:15.794634", "\074\072\164\109\249\213\236\064" ; 5, 48, 28, 500, 210, "05:48:28.500210", "\200\205\112\003\032\107\212\064" ; 10, 6, 57, 472, 906, "10:06:57.472906", "\131\195\011\034\047\200\225\064" ; 9, 27, 31, 617, 312, "09:27:31.617312", "\109\024\005\193\115\160\224\064" ; 22, 12, 39, 522, 109, "22:12:39.522109", "\127\247\142\090\120\133\243\064" ; 8, 51, 53, 900, 226, "08:51:53.900226", "\065\131\077\157\121\042\223\064" ; 18, 36, 35, 57, 526, "18:36:35.057526", "\011\098\160\235\048\091\240\064" ; 2, 13, 23, 259, 111, "02:13:23.259111", "\009\055\025\085\066\067\191\064" ; 23, 2, 29, 279, 746, "23:02:29.279746", "\019\241\214\121\084\064\244\064" ; 6, 58, 43, 122, 300, "06:58:43.122300", "\019\097\195\211\199\136\216\064" ; 11, 10, 49, 575, 648, "11:10:49.575648", "\192\090\181\107\050\167\227\064" ; 9, 52, 51, 893, 693, "09:52:51.893693", "\245\015\034\153\124\094\225\064" ; 4, 50, 34, 788, 521, "04:50:34.788521", "\206\200\032\119\178\006\209\064" ; 5, 42, 53, 940, 355, "05:42:53.940355", "\232\188\198\046\124\023\212\064" ; 19, 9, 21, 923, 277, "19:09:21.923277", "\130\026\190\197\030\214\240\064" ; 4, 14, 48, 973, 749, "04:14:48.973749", "\194\166\206\163\124\220\205\064" ; 23, 6, 43, 95, 327, "23:06:43.095327", "\183\154\117\134\049\080\244\064" ; 11, 53, 5, 288, 161, "11:53:05.288161", "\224\106\157\056\041\228\228\064" ; 3, 35, 11, 229, 39, "03:35:11.229039", "\065\099\038\081\157\055\201\064" ; 18, 23, 40, 213, 626, "18:23:40.213626", "\185\024\003\107\195\042\240\064" ; 18, 48, 3, 407, 241, "18:48:03.407241", "\138\035\015\132\054\134\240\064" ; 7, 37, 24, 227, 629, "07:37:24.227629", "\167\057\121\145\014\205\218\064" ; 20, 9, 37, 995, 781, "20:09:37.995781", "\207\014\184\238\031\184\241\064" ; 1, 56, 19, 267, 355, "01:56:19.267355", "\108\149\096\113\068\067\187\064" ; 4, 50, 1, 197, 354, "04:50:01.197354", "\239\171\114\161\076\254\208\064" ; 2, 39, 18, 16, 829, "02:39:18.016829", "\080\226\115\039\002\171\194\064" ; 8, 11, 33, 943, 2, "08:11:33.943002", "\132\015\037\090\124\205\220\064" ; 18, 24, 14, 8, 828, "18:24:14.008828", "\053\212\040\036\224\044\240\064" ; 6, 16, 40, 615, 986, "06:16:40.615986", "\051\139\080\108\039\018\214\064" ; 8, 56, 12, 92, 776, "08:56:12.092776", "\119\191\010\240\005\107\223\064" ; 0, 46, 5, 83, 964, "00:46:05.083964", "\021\084\084\253\042\154\165\064" ; 12, 20, 6, 567, 402, "12:20:06.567402", "\054\061\040\040\210\174\229\064" ; 4, 28, 40, 897, 126, "04:28:40.897126", "\051\087\006\213\114\124\207\064" ; 0, 23, 10, 147, 660, "00:23:10.147660", "\181\219\046\052\151\184\149\064" ; 10, 58, 22, 191, 950, "10:58:22.191950", "\143\083\116\036\198\073\227\064" ; 6, 8, 35, 57, 15, "06:08:35.057015", "\025\062\034\166\195\152\213\064" ; 3, 56, 1, 84, 286, "03:56:01.084286", "\194\054\226\201\138\168\203\064" ; 13, 5, 40, 152, 369, "13:05:40.152369", "\254\243\052\224\132\004\231\064" ; 20, 17, 45, 424, 123, "20:17:45.424123", "\232\050\053\201\150\214\241\064" ; 5, 51, 38, 196, 855, "05:51:38.196855", "\195\182\069\153\140\154\212\064" ; 21, 32, 14, 760, 951, "21:32:14.760951", "\173\244\218\044\236\237\242\064" ; 17, 29, 10, 307, 464, "17:29:10.307464", "\022\190\190\214\201\188\238\064" ; 0, 50, 23, 440, 612, "00:50:23.440612", "\115\100\229\151\225\158\167\064" ; 2, 15, 26, 25, 555, "02:15:26.025555", "\063\193\197\138\006\190\191\064" ; 11, 40, 37, 264, 469, "11:40:37.264469", "\058\177\135\118\168\134\228\064" ; 23, 17, 26, 403, 761, "23:17:26.403761", "\039\024\206\117\102\120\244\064" ; 3, 28, 8, 631, 502, "03:28:08.631502", "\174\186\014\213\080\100\200\064" ; 11, 39, 24, 4, 755, "11:39:24.004755", "\048\245\243\038\128\125\228\064" ; 16, 39, 3, 164, 296, "16:39:03.164296", "\091\175\233\065\229\068\237\064" ; 2, 27, 12, 25, 495, "02:27:12.025495", "\155\143\107\067\003\064\193\064" ; 1, 35, 51, 15, 854, "01:35:51.015854", "\131\251\001\015\004\119\182\064" ; 14, 57, 47, 846, 758, "14:57:47.846758", "\180\059\164\024\123\077\234\064" ; 17, 17, 13, 717, 130, "17:17:13.717130", "\031\157\186\242\054\099\238\064" ; 4, 43, 9, 843, 283, "04:43:09.843283", "\146\066\089\248\117\151\208\064" ; 12, 43, 20, 24, 790, "12:43:20.024790", "\232\101\020\203\000\093\230\064" ; 23, 31, 2, 619, 664, "23:31:02.619664", "\105\204\036\234\105\171\244\064" ; 6, 45, 53, 822, 33, "06:45:53.822033", "\207\076\048\156\116\200\215\064" ; 21, 54, 40, 325, 644, "21:54:40.325644", "\162\123\214\053\005\066\243\064" ; 15, 10, 26, 53, 713, "15:10:26.053713", "\076\083\004\184\065\172\234\064" ; 12, 24, 22, 848, 557, "12:24:22.848557", "\121\002\097\039\219\206\229\064" ; 14, 2, 19, 877, 339, "14:02:19.877339", "\016\061\041\019\124\173\232\064" ; 17, 29, 6, 164, 668, "17:29:06.164668", "\086\211\245\068\069\188\238\064" ; 5, 21, 11, 861, 201, "05:21:11.861201", "\146\204\234\029\247\209\210\064" ; 7, 39, 31, 205, 367, "07:39:31.205367", "\044\161\187\036\205\236\218\064" ; 11, 11, 37, 400, 431, "11:11:37.400431", "\042\172\084\208\044\173\227\064" ; 16, 36, 2, 209, 616, "16:36:02.209616", "\023\157\044\181\070\046\237\064" ; 6, 43, 37, 247, 198, "06:43:37.247198", "\105\143\023\210\079\166\215\064" ; 16, 28, 36, 676, 940, "16:28:36.676940", "\043\019\126\169\149\246\236\064" ; 20, 3, 35, 896, 664, "20:03:35.896664", "\184\089\188\088\126\161\241\064" ; 1, 15, 7, 496, 788, "01:15:07.496788", "\012\149\127\045\127\155\177\064" ; 18, 33, 4, 683, 950, "18:33:04.683950", "\034\142\117\241\010\078\240\064" ; 13, 55, 37, 616, 282, "13:55:37.616282", "\100\007\149\184\051\123\232\064" ; 13, 21, 28, 456, 231, "13:21:28.456231", "\013\193\113\153\014\123\231\064" ; 5, 35, 51, 592, 290, "05:35:51.592290", "\240\080\020\232\229\173\211\064" ; 23, 5, 39, 295, 602, "23:05:39.295602", "\170\041\201\186\052\076\244\064" ; 13, 11, 16, 982, 624, "13:11:16.982624", "\009\227\167\113\159\046\231\064" ; 8, 2, 23, 191, 227, "08:02:23.191227", "\199\043\016\061\204\067\220\064" ; 7, 13, 47, 171, 589, "07:13:47.171589", "\214\109\080\251\202\106\217\064" ; 13, 30, 9, 613, 547, "13:30:09.613547", "\114\081\045\162\051\188\231\064" ; 12, 33, 32, 116, 766, "12:33:32.116766", "\233\012\140\188\131\019\230\064" ; 18, 14, 6, 621, 189, "18:14:06.621189", "\122\224\099\240\233\006\240\064" ; 15, 41, 12, 210, 108, "15:41:12.210108", "\148\105\052\185\006\147\235\064" ; 9, 45, 58, 324, 300, "09:45:58.324300", "\195\100\170\096\202\042\225\064" ; 0, 52, 36, 787, 772, "00:52:36.787772", "\104\001\218\086\147\169\168\064" ; 6, 35, 54, 954, 904, "06:35:54.954904", "\181\170\037\029\189\050\215\064" ; 5, 50, 14, 914, 808, "05:50:14.914808", "\136\218\054\140\186\133\212\064" ; 6, 49, 11, 820, 225, "06:49:11.820225", "\151\255\144\126\244\249\215\064" ; 13, 21, 40, 497, 927, "13:21:40.497927", "\154\154\004\239\143\124\231\064" ; 14, 24, 47, 509, 819, "14:24:47.509819", "\124\239\111\080\240\085\233\064" ; 2, 31, 8, 578, 920, "02:31:08.578920", "\128\241\012\026\074\182\193\064" ; 20, 50, 4, 950, 916, "20:50:04.950916", "\020\178\243\054\207\079\242\064" ; 17, 15, 43, 91, 571, "17:15:43.091571", "\072\078\038\238\226\087\238\064" ; 21, 7, 9, 817, 314, "21:07:09.817314", "\073\216\183\019\221\143\242\064" ; 3, 50, 31, 665, 810, "03:50:31.665810", "\173\023\067\057\213\003\203\064" ; 22, 20, 29, 216, 897, "22:20:29.216897", "\026\253\104\120\211\162\243\064" ; 1, 50, 59, 302, 281, "01:50:59.302281", "\051\161\073\098\077\003\186\064" ; 2, 10, 59, 454, 508, "02:10:59.454508", "\197\227\162\090\116\179\190\064" ; 12, 37, 29, 483, 812, "12:37:29.483812", "\173\077\099\123\047\049\230\064" ; 7, 21, 36, 911, 469, "07:21:36.911469", "\148\018\130\085\058\224\217\064" ; 16, 4, 20, 641, 723, "16:04:20.641723", "\067\172\254\136\148\064\236\064" ; 4, 5, 48, 895, 883, "04:05:48.895883", "\006\077\075\172\114\206\204\064" ; 15, 12, 1, 715, 2, "15:12:01.715002", "\210\223\075\225\054\184\234\064" ; 6, 40, 11, 285, 152, "06:40:11.285152", "\153\044\238\063\210\114\215\064" ; 6, 27, 31, 646, 343, "06:27:31.646343", "\192\007\175\093\233\180\214\064" ; 6, 25, 44, 511, 245, "06:25:44.511245", "\207\242\060\184\032\154\214\064" ; 12, 28, 44, 619, 561, "12:28:44.619561", "\028\151\113\211\147\239\229\064" ; 16, 36, 43, 938, 41, "16:36:43.938041", "\042\143\110\004\126\051\237\064" ; 12, 24, 25, 727, 786, "12:24:25.727786", "\143\221\005\074\055\207\229\064" ; 18, 28, 18, 750, 721, "18:28:18.750721", "\247\005\244\002\044\060\240\064" ; 21, 45, 24, 965, 295, "21:45:24.965295", "\128\043\217\113\079\031\243\064" ; 1, 39, 49, 298, 201, "01:39:49.298201", "\162\150\230\086\076\101\183\064" ; 16, 28, 40, 479, 603, "16:28:40.479603", "\002\100\232\088\015\247\236\064" ; 5, 39, 40, 919, 372, "05:39:40.919372", "\055\168\253\214\058\231\211\064" ; 9, 20, 35, 164, 109, "09:20:35.164109", "\127\132\097\064\101\108\224\064" ; 15, 39, 15, 350, 721, "15:39:15.350721", "\032\063\027\057\107\132\235\064" ; 7, 20, 17, 677, 966, "07:20:17.677966", "\115\129\203\099\107\204\217\064" ; 0, 39, 33, 404, 1, "00:39:33.404001", "\026\021\056\217\206\138\162\064" ; 10, 38, 20, 157, 76, "10:38:20.157076", "\095\063\196\006\133\179\226\064" ; 8, 19, 0, 241, 148, "08:19:00.241148", "\096\005\248\110\015\061\221\064" ; 12, 32, 1, 718, 382, "12:32:01.718382", "\129\063\252\252\054\008\230\064" ; 2, 8, 46, 463, 579, "02:08:46.463579", "\028\004\029\173\118\046\190\064" ; 0, 38, 8, 410, 846, "00:38:08.410846", "\098\043\104\090\210\224\161\064" ; 8, 19, 1, 898, 138, "08:19:01.898138", "\083\206\023\123\121\061\221\064" ; 16, 45, 5, 40, 20, "16:45:05.040020", "\230\005\216\071\033\114\237\064" ; 11, 45, 42, 132, 71, "11:45:42.132071", "\056\246\236\057\196\172\228\064" ; 2, 9, 47, 604, 168, "02:09:47.604168", "\074\009\193\170\154\107\190\064" ; 1, 18, 57, 714, 130, "01:18:57.714130", "\024\067\057\209\182\129\178\064" ; 15, 51, 50, 211, 589, "15:51:50.211589", "\103\075\086\197\198\226\235\064" ; 23, 44, 44, 934, 605, "23:44:44.934605", "\090\095\036\244\206\222\244\064" ; 4, 40, 43, 952, 302, "04:40:43.952302", "\123\022\132\242\252\114\208\064" ; 20, 39, 41, 296, 558, "20:39:41.296558", "\246\153\179\190\212\040\242\064" ; 19, 21, 49, 310, 369, "19:21:49.310369", "\011\124\069\247\212\004\241\064" ; 23, 29, 41, 810, 479, "23:29:41.810479", "\241\211\184\247\092\166\244\064" ; 1, 20, 21, 363, 313, "01:20:21.363313", "\054\173\020\002\093\213\178\064" ; 5, 59, 48, 953, 133, "05:59:48.953133", "\240\141\033\000\061\021\213\064" ; 12, 33, 50, 349, 580, "12:33:50.349580", "\107\101\194\047\203\021\230\064" ; 4, 20, 57, 101, 495, "04:20:57.101495", "\219\196\201\253\140\148\206\064" ; 8, 28, 46, 68, 654, "08:28:46.068654", "\047\191\211\100\132\207\221\064" ; 18, 17, 11, 854, 90, "18:17:11.854090", "\158\070\090\170\125\018\240\064" ; 10, 54, 54, 221, 184, "10:54:54.221184", "\204\119\240\019\199\047\227\064" ; 19, 24, 29, 680, 261, "19:24:29.680261", "\187\091\089\226\218\014\241\064" ; 9, 40, 24, 761, 592, "09:40:24.761592", "\156\047\246\094\024\001\225\064" ; 7, 6, 20, 251, 770, "07:06:20.251770", "\007\235\255\028\016\251\216\064" ; 12, 35, 44, 108, 412, "12:35:44.108412", "\080\113\028\120\003\036\230\064" ; 12, 5, 16, 11, 549, "12:05:16.011549", "\041\002\156\094\128\063\229\064" ; 4, 43, 26, 479, 133, "04:43:26.479133", "\092\117\029\170\158\155\208\064" ; 12, 6, 1, 740, 361, "12:06:01.740361", "\071\141\009\177\055\069\229\064" ; 9, 31, 54, 181, 266, "09:31:54.181266", "\188\090\238\204\069\193\224\064" ; 7, 22, 15, 59, 587, "07:22:15.059587", "\017\254\069\208\195\233\217\064" ; 11, 8, 23, 233, 750, "11:08:23.233750", "\174\071\225\122\231\148\227\064" ; 9, 13, 33, 973, 924, "09:13:33.973924", "\025\170\098\042\191\055\224\064" ; 6, 50, 25, 864, 837, "06:50:25.864837", "\216\073\125\089\119\012\216\064" ; 11, 34, 5, 212, 813, "11:34:05.212813", "\101\053\093\207\166\085\228\064" ; 11, 4, 15, 316, 210, "11:04:15.316210", "\021\111\100\030\234\117\227\064" ; 0, 14, 58, 558, 913, "00:14:58.558913", "\121\002\097\167\120\020\140\064" ; 19, 23, 34, 378, 889, "19:23:34.378889", "\125\233\237\015\102\011\241\064" ; 7, 22, 5, 684, 575, "07:22:05.684575", "\042\169\019\208\107\231\217\064" ; 14, 53, 25, 936, 378, "14:53:25.936378", "\214\254\206\246\189\044\234\064" ; 23, 28, 0, 16, 128, "23:28:00.016128", "\009\111\015\066\000\160\244\064" ; 7, 33, 24, 239, 340, "07:33:24.239340", "\040\184\088\081\015\145\218\064" ; 9, 9, 43, 846, 833, "09:09:43.846833", "\005\133\065\025\251\026\224\064" ; 8, 44, 52, 482, 797, "08:44:52.482797", "\103\099\037\230\030\193\222\064" ; 5, 4, 12, 976, 758, "05:04:12.976758", "\134\252\051\131\062\211\209\064" ; 16, 46, 58, 849, 155, "16:46:58.849155", "\072\027\071\044\091\128\237\064" ; 6, 7, 53, 48, 203, "06:07:53.048203", "\036\009\194\021\067\142\213\064" ; 9, 53, 57, 30, 571, "09:53:57.030571", "\166\008\112\250\160\102\225\064" ; 7, 17, 38, 251, 966, "07:17:38.251966", "\109\000\054\032\144\164\217\064" ; 21, 52, 26, 497, 300, "21:52:26.497300", "\069\216\240\244\167\057\243\064" ; 7, 3, 51, 972, 980, "07:03:51.972980", "\235\231\077\069\254\213\216\064" ; 23, 28, 25, 478, 512, "23:28:25.478512", "\236\050\252\167\151\161\244\064" ; 3, 16, 41, 328, 822, "03:16:41.328822", "\026\220\214\022\170\012\199\064" ; 2, 35, 59, 538, 765, "02:35:59.538765", "\158\099\064\246\196\071\194\064" ; 10, 46, 8, 897, 226, "10:46:08.897226", "\227\076\019\182\028\238\226\064" ; 18, 48, 28, 110, 976, "18:48:28.110976", "\042\197\142\198\193\135\240\064" ; 7, 1, 32, 937, 845, "07:01:32.937845", "\238\008\167\005\060\179\216\064" ; 3, 0, 48, 386, 487, "03:00:48.386487", "\170\240\103\120\049\048\197\064" ; 12, 23, 15, 739, 882, "12:23:15.739882", "\029\004\029\173\119\198\229\064" ; 20, 34, 52, 701, 220, "20:34:52.701220", "\117\118\050\056\203\022\242\064" ; 15, 27, 23, 562, 837, "15:27:23.562837", "\127\189\194\002\114\043\235\064" ; 6, 13, 12, 587, 973, "06:13:12.587973", "\123\129\089\161\037\222\213\064" ; 16, 5, 36, 81, 296, "16:05:36.081296", "\169\017\250\153\002\074\236\064" ; 20, 18, 16, 348, 202, "20:18:16.348202", "\166\066\060\146\133\216\241\064" ; 21, 26, 16, 625, 627, "21:26:16.625627", "\008\117\145\002\138\215\242\064" ; 13, 31, 36, 39, 478, "13:31:36.039478", "\221\093\103\067\001\199\231\064" ; 9, 9, 36, 970, 585, "09:09:36.970585", "\032\070\008\015\031\026\224\064" ; 23, 44, 54, 272, 794, "23:44:54.272794", "\201\061\093\093\100\223\244\064" ; 6, 5, 21, 652, 759, "06:05:21.652759", "\074\175\205\198\105\104\213\064" ; 4, 15, 6, 577, 731, "04:15:06.577731", "\113\227\022\243\073\229\205\064" ; 10, 37, 13, 375, 924, "10:37:13.375924", "\185\196\145\007\044\171\226\064" ; 22, 45, 38, 539, 556, "22:45:38.539556", "\230\120\005\162\040\001\244\064" ; 15, 52, 43, 413, 314, "15:52:43.413314", "\031\072\222\057\109\233\235\064" ; 4, 51, 17, 321, 150, "04:51:17.321150", "\199\186\184\141\084\017\209\064" ; 8, 46, 15, 966, 204, "08:46:15.966204", "\081\077\073\214\253\213\222\064" ; 5, 49, 25, 452, 167, "05:49:25.452167", "\085\219\077\240\092\121\212\064" ; 14, 59, 57, 237, 285, "14:59:57.237285", "\091\182\214\151\167\093\234\064" ; 9, 23, 32, 643, 823, "09:23:32.643823", "\045\177\050\154\148\130\224\064" ; 14, 45, 47, 489, 889, "14:45:47.489889", "\054\178\043\173\111\243\233\064" ; 3, 6, 7, 475, 348, "03:06:07.475348", "\028\009\052\216\188\207\197\064" ; 13, 37, 11, 57, 446, "13:37:11.057446", "\105\254\152\214\225\240\231\064" ; 1, 55, 47, 541, 568, "01:55:47.541568", "\144\080\051\164\138\035\187\064" ; 10, 32, 31, 923, 814, "10:32:31.923814", "\179\096\226\143\253\135\226\064" ; 22, 48, 9, 866, 29, "22:48:09.866029", "\134\057\065\219\157\010\244\064" ; 2, 48, 33, 944, 998, "02:48:33.944998", "\100\200\177\245\248\192\195\064" ; 8, 13, 4, 807, 276, "08:13:04.807276", "\182\244\104\170\051\228\220\064" ; 14, 53, 44, 558, 232, "14:53:44.558232", "\242\090\009\221\017\047\234\064" ; 7, 19, 59, 579, 78, "07:19:59.579078", "\246\043\157\015\229\199\217\064" ; 16, 54, 25, 830, 67, "16:54:25.830067", "\080\171\232\143\058\184\237\064" ; 1, 41, 14, 586, 870, "01:41:14.586870", "\001\193\028\061\150\186\183\064" ; 15, 58, 14, 676, 214, "15:58:14.676214", "\227\138\139\163\213\018\236\064" ; 10, 37, 18, 335, 153, "10:37:18.335153", "\197\200\146\185\202\171\226\064" ; 7, 52, 39, 177, 512, "07:52:39.177512", "\169\074\091\092\203\177\219\064" ; 22, 17, 6, 751, 455, "22:17:06.751455", "\151\173\245\005\044\150\243\064" ; 11, 17, 36, 421, 79, "11:17:36.421079", "\193\170\122\121\013\218\227\064" ; 17, 24, 0, 311, 282, "17:24:00.311282", "\059\171\005\246\009\150\238\064" ; 20, 5, 50, 167, 508, "20:05:50.167508", "\093\222\028\174\226\169\241\064" ; 17, 27, 20, 142, 542, "17:27:20.142542", "\138\061\180\143\004\175\238\064" ; 16, 26, 16, 718, 680, "16:26:16.718680", "\009\051\109\255\022\229\236\064" ; 18, 58, 22, 922, 172, "18:58:22.922172", "\085\109\055\193\238\172\240\064" ; 17, 43, 22, 239, 754, "17:43:22.239754", "\163\148\016\172\071\039\239\064" ; 1, 13, 45, 723, 36, "01:13:45.723036", "\213\037\227\024\185\073\177\064" ; 12, 34, 6, 605, 806, "12:34:06.605806", "\183\067\195\098\211\023\230\064" ; 1, 59, 31, 103, 366, "01:59:31.103366", "\133\181\049\118\026\003\188\064" ; 17, 14, 27, 443, 506, "17:14:27.443506", "\178\126\051\049\110\078\238\064" ; 19, 42, 20, 246, 315, "19:42:20.246315", "\088\255\231\240\195\081\241\064" ; 11, 42, 19, 370, 14, "11:42:19.370014", "\162\153\039\215\107\147\228\064" ; 11, 41, 27, 688, 243, "11:41:27.688243", "\023\047\022\006\246\140\228\064" ; 18, 59, 21, 337, 61, "18:59:21.337061", "\060\019\154\100\149\176\240\064" ; 4, 0, 26, 663, 900, "04:00:26.663900", "\232\217\172\250\084\045\204\064" ; 4, 19, 34, 477, 480, "04:19:34.477480", "\064\140\016\030\061\107\206\064" ; 13, 30, 59, 114, 583, "13:30:59.114583", "\182\247\169\170\099\194\231\064" ; 18, 5, 29, 717, 905, "18:05:29.717905", "\020\232\019\249\054\205\239\064" ; 19, 12, 59, 981, 614, "19:12:59.981614", "\181\225\176\180\191\227\240\064" ; 16, 10, 49, 758, 762, "16:10:49.758762", "\239\062\199\071\056\113\236\064" ; 8, 50, 33, 394, 992, "08:50:33.394992", "\140\134\140\071\089\022\223\064" ; 8, 12, 22, 671, 487, "08:12:22.671487", "\044\156\164\249\170\217\220\064" ; 2, 5, 52, 168, 66, "02:05:52.168066", "\145\149\095\006\043\128\189\064" ; 6, 19, 36, 681, 610, "06:19:36.681610", "\168\140\127\159\043\062\214\064" ; 5, 30, 45, 662, 912, "05:30:45.662912", "\008\116\038\109\106\097\211\064" ; 7, 25, 54, 388, 701, "07:25:54.388701", "\187\040\122\224\152\032\218\064" ; 18, 56, 16, 136, 935, "18:56:16.136935", "\043\193\226\048\002\165\240\064" ; 19, 39, 10, 170, 39, "19:39:10.170039", "\129\208\122\184\226\069\241\064" ; 21, 30, 55, 480, 722, "21:30:55.480722", "\071\141\009\177\247\232\242\064" ; 0, 56, 32, 307, 505, "00:56:32.307505", "\182\156\075\113\157\128\170\064" ; 15, 4, 31, 155, 783, "15:04:31.155783", "\073\161\044\252\228\127\234\064" ; 2, 13, 58, 457, 125, "02:13:58.457125", "\047\221\036\006\117\102\191\064" ; 4, 47, 57, 977, 382, "04:47:57.977382", "\108\059\109\141\126\223\208\064" ; 7, 2, 37, 557, 905, "07:02:37.557905", "\082\044\183\180\099\195\216\064" ; 18, 36, 7, 359, 818, "18:36:07.359818", "\232\132\208\193\117\089\240\064" ; 6, 37, 6, 298, 809, "06:37:06.298809", "\176\200\175\031\147\068\215\064" ; 8, 14, 2, 917, 956, "08:14:02.917956", "\203\133\202\191\186\242\220\064" ; 10, 57, 26, 371, 154, "10:57:26.371154", "\121\090\126\224\203\066\227\064" ; 7, 14, 10, 852, 591, "07:14:10.852591", "\119\215\217\144\182\112\217\064" ; 21, 5, 47, 584, 964, "21:05:47.584964", "\022\054\003\092\185\138\242\064" ; 17, 10, 1, 21, 820, "17:10:01.021820", "\077\219\191\178\032\045\238\064" ; 12, 24, 41, 986, 177, "12:24:41.986177", "\098\017\195\142\063\209\229\064" ; 22, 42, 21, 449, 610, "22:42:21.449610", "\095\065\154\049\215\244\243\064" ; 23, 48, 30, 702, 495, "23:48:30.702495", "\170\101\107\061\235\236\244\064" ; 0, 43, 5, 352, 361, "00:43:05.352361", "\197\054\169\104\180\050\164\064" ; 12, 18, 46, 96, 352, "12:18:46.096352", "\029\202\080\021\195\164\229\064" ; 17, 51, 46, 363, 998, "17:51:46.363998", "\058\034\223\165\075\102\239\064" ; 3, 1, 4, 772, 971, "03:01:04.772971", "\225\182\182\240\098\056\197\064" ; 17, 29, 43, 167, 780, "17:29:43.167780", "\158\041\116\094\229\192\238\064" ; 7, 53, 21, 562, 946, "07:53:21.562946", "\219\168\078\007\100\188\219\064" ; 17, 6, 32, 107, 378, "17:06:32.107378", "\202\252\163\111\003\019\238\064" ; 19, 41, 17, 161, 766, "19:41:17.161766", "\249\241\151\150\210\077\241\064" ; 7, 30, 18, 883, 425, "07:30:18.883425", "\222\002\009\138\184\098\218\064" ; 23, 31, 57, 34, 672, "23:31:57.034672", "\033\058\004\142\208\174\244\064" ; 16, 55, 13, 615, 853, "16:55:13.615853", "\196\089\017\181\051\190\237\064" ; 14, 49, 24, 777, 856, "14:49:24.777856", "\032\068\050\228\152\014\234\064" ; 7, 18, 39, 618, 28, "07:18:39.618028", "\000\080\197\141\231\179\217\064" ; 21, 30, 31, 937, 591, "21:30:31.937591", "\161\107\095\000\127\231\242\064" ; 22, 23, 28, 681, 947, "22:23:28.681947", "\233\065\065\233\010\174\243\064" ; 1, 51, 53, 35, 245, "01:51:53.035245", "\089\250\208\005\009\057\186\064" ; 8, 49, 6, 614, 842, "08:49:06.614842", "\142\066\146\089\167\000\223\064" ; 2, 44, 9, 955, 831, "02:44:09.955831", "\192\146\171\088\250\060\195\064" ; 20, 58, 55, 812, 699, "20:58:55.812699", "\168\170\208\000\253\112\242\064" ; 23, 22, 14, 862, 459, "23:22:14.862459", "\242\206\161\204\109\138\244\064" ; 21, 39, 18, 65, 66, "21:39:18.065066", "\097\165\130\010\097\008\243\064" ; 15, 5, 57, 766, 253, "15:05:57.766253", "\239\002\037\133\184\138\234\064" ; 14, 29, 55, 548, 811, "14:29:55.548811", "\022\022\220\143\113\124\233\064" ; 19, 13, 26, 400, 747, "19:13:26.400747", "\175\175\117\105\102\229\240\064" ; 17, 17, 59, 491, 507, "17:17:59.491507", "\088\227\108\186\239\104\238\064" ; 8, 53, 19, 593, 142, "08:53:19.593142", "\249\220\009\246\229\063\223\064" ; 16, 45, 19, 824, 689, "16:45:19.824689", "\140\047\218\099\250\115\237\064" ; 15, 54, 55, 419, 539, "15:54:55.419539", "\141\013\221\108\237\249\235\064" ; 9, 41, 53, 503, 256, "09:41:53.503256", "\176\083\172\026\048\012\225\064" ; 21, 30, 9, 313, 171, "21:30:09.313171", "\049\152\191\002\021\230\242\064" ; 8, 24, 4, 959, 594, "08:24:04.959594", "\220\243\252\105\061\137\221\064" ; 21, 53, 17, 925, 973, "21:53:17.925973", "\128\016\201\208\222\060\243\064" ; 18, 20, 45, 472, 635, "18:20:45.472635", "\191\183\233\143\215\031\240\064" ; 15, 41, 26, 487, 523, "15:41:26.487523", "\162\213\201\153\207\148\235\064" ; 20, 11, 36, 148, 846, "20:11:36.148846", "\226\087\172\097\130\191\241\064" ; 16, 49, 50, 36, 969, "16:49:50.036969", "\191\156\217\046\193\149\237\064" ; 2, 3, 40, 65, 867, "02:03:40.065867", "\226\226\168\220\016\252\188\064" ; 7, 37, 22, 964, 291, "07:37:22.964291", "\053\153\241\182\189\204\218\064" ; 0, 33, 39, 965, 773, "00:33:39.965773", "\112\233\152\243\220\143\159\064" ; 16, 18, 49, 465, 399, "16:18:49.465399", "\146\113\140\228\046\173\236\064" ; 5, 11, 10, 807, 397, "05:11:10.807397", "\121\119\100\172\179\059\210\064" ; 10, 36, 2, 961, 178, "10:36:02.961178", "\117\093\248\193\094\162\226\064" ; 14, 24, 14, 719, 395, "14:24:14.719395", "\189\169\072\005\215\081\233\064" ; 3, 11, 26, 747, 972, "03:11:26.747972", "\041\231\139\189\095\111\198\064" ; 22, 6, 38, 786, 354, "22:06:38.786354", "\145\238\231\148\236\110\243\064" ; 12, 7, 32, 759, 248, "12:07:32.759248", "\049\118\194\075\152\080\229\064" ; 13, 13, 55, 973, 573, "13:13:55.973573", "\104\144\130\039\127\066\231\064" ; 18, 24, 14, 338, 831, "18:24:14.338831", "\254\013\218\107\229\044\240\064" ; 19, 3, 38, 45, 344, "19:03:38.045344", "\081\161\186\185\160\192\240\064" ; 15, 28, 22, 915, 198, "15:28:22.915198", "\236\080\077\073\221\050\235\064" ; 20, 32, 55, 159, 494, "20:32:55.159494", "\159\148\073\141\114\015\242\064" ; 13, 11, 15, 249, 789, "13:11:15.249789", "\061\128\069\254\103\046\231\064" ; 2, 11, 51, 926, 900, "02:11:51.926900", "\170\130\081\073\237\231\190\064" ; 13, 57, 24, 962, 924, "13:57:24.962924", "\017\254\069\208\158\136\232\064" ; 22, 1, 37, 921, 80, "22:01:37.921080", "\208\097\190\188\030\092\243\064" ; 18, 40, 36, 10, 160, "18:40:36.010160", "\059\136\157\041\064\106\240\064" ; 17, 13, 34, 68, 875, "17:13:34.068875", "\016\088\057\052\194\071\238\064" ; 19, 57, 2, 253, 866, "19:57:02.253866", "\121\203\213\015\228\136\241\064" ; 21, 57, 58, 989, 629, "21:57:58.989629", "\227\055\133\213\111\078\243\064" ; 23, 31, 47, 135, 113, "23:31:47.135113", "\196\063\108\041\050\174\244\064" ; 4, 54, 9, 358, 522, "04:54:09.358522", "\057\066\006\242\086\060\209\064" ; 3, 14, 15, 973, 189, "03:14:15.973189", "\234\007\117\145\252\195\198\064" ; 9, 20, 55, 505, 999, "09:20:55.505999", "\154\208\036\049\240\110\224\064" ; 23, 56, 58, 368, 158, "23:56:58.368158", "\156\164\249\227\165\012\245\064" ; 5, 29, 9, 887, 758, "05:29:09.887758", "\048\238\006\209\120\073\211\064" ; 20, 2, 55, 153, 680, "20:02:55.153680", "\225\040\121\117\242\158\241\064" ; 16, 52, 27, 608, 596, "16:52:27.608596", "\143\081\158\121\115\169\237\064" ; 13, 58, 5, 713, 17, "13:58:05.713017", "\016\007\009\209\182\141\232\064" ; 2, 5, 49, 295, 856, "02:05:49.295856", "\083\004\056\189\075\125\189\064" ; 6, 40, 53, 111, 944, "06:40:53.111944", "\191\042\023\042\071\125\215\064" ; 14, 30, 16, 777, 619, "14:30:16.777619", "\184\061\065\226\024\127\233\064" ; 6, 32, 9, 139, 368, "06:32:09.139368", "\135\194\103\235\072\250\214\064" ; 11, 32, 20, 41, 875, "11:32:20.041875", "\112\061\010\087\129\072\228\064" ; 5, 30, 40, 676, 71, "05:30:40.676071", "\177\076\191\068\043\096\211\064" ; 6, 17, 59, 904, 587, "06:17:59.904587", "\088\223\192\228\249\037\214\064" ; 15, 58, 24, 266, 222, "15:58:24.266222", "\240\255\227\132\008\020\236\064" ; 15, 54, 9, 878, 473, "15:54:09.878473", "\173\104\115\028\060\244\235\064" ; 18, 47, 3, 329, 441, "18:47:03.329441", "\015\237\099\069\117\130\240\064" ; 21, 38, 11, 629, 135, "21:38:11.629135", "\156\220\239\016\058\004\243\064" ; 3, 10, 0, 959, 733, "03:10:00.959733", "\243\235\135\216\122\068\198\064" ; 12, 35, 15, 736, 975, "12:35:15.736975", "\095\152\076\149\119\032\230\064" ; 16, 7, 30, 83, 823, "16:07:30.083823", "\117\146\173\174\066\088\236\064" ; 20, 25, 33, 890, 843, "20:25:33.890843", "\238\150\228\064\222\243\241\064" ; 16, 20, 36, 429, 59, "16:20:36.429059", "\161\240\217\186\141\186\236\064" ; 10, 36, 2, 434, 479, "10:36:02.434479", "\250\128\064\231\077\162\226\064" ; 0, 45, 59, 664, 504, "00:45:59.664504", "\032\072\222\057\084\143\165\064" ; 0, 6, 57, 199, 632, "00:06:57.199632", "\195\243\082\177\049\019\122\064" ; 13, 17, 16, 804, 597, "13:17:16.804597", "\046\053\066\191\153\091\231\064" ; 9, 49, 29, 262, 408, "09:49:29.262408", "\071\118\165\101\040\069\225\064" ; 7, 14, 8, 715, 806, "07:14:08.715806", "\018\248\195\207\045\112\217\064" ; 15, 46, 41, 44, 658, "15:46:41.044658", "\048\157\214\109\033\188\235\064" ; 11, 8, 32, 266, 443, "11:08:32.266443", "\104\120\179\134\008\150\227\064" ; 22, 0, 56, 728, 51, "22:00:56.728051", "\045\206\024\166\139\089\243\064" ; 7, 13, 37, 872, 961, "07:13:37.872961", "\108\208\151\222\119\104\217\064" ; 8, 33, 6, 204, 458, "08:33:06.204458", "\218\001\215\021\141\016\222\064" ; 21, 17, 8, 374, 152, "21:17:08.374152", "\187\206\134\252\069\181\242\064" ; 3, 49, 27, 919, 301, "03:49:27.919301", "\023\185\167\171\245\227\202\064" ; 10, 48, 37, 644, 839, "10:48:37.644839", "\006\102\133\162\180\000\227\064" ; 8, 16, 42, 40, 502, "08:16:42.040502", "\091\179\149\151\130\026\221\064" ; 19, 40, 48, 432, 338, "19:40:48.432338", "\045\064\219\234\006\076\241\064" ; 18, 22, 25, 392, 703, "18:22:25.392703", "\225\240\130\072\022\038\240\064" ; 18, 28, 0, 28, 196, "18:28:00.028196", "\030\166\125\115\000\059\240\064" ; 18, 45, 52, 497, 508, "18:45:52.497508", "\216\242\202\245\007\126\240\064" ; 8, 10, 21, 555, 639, "08:10:21.555639", "\089\225\150\143\099\187\220\064" ; 9, 56, 15, 632, 934, "09:56:15.632934", "\209\205\254\064\244\119\225\064" ; 22, 17, 5, 993, 11, "22:17:05.993011", "\153\128\095\227\031\150\243\064" ; 16, 35, 32, 105, 73, "16:35:32.105073", "\087\013\194\092\131\042\237\064" ; 13, 23, 13, 395, 302, "13:23:13.395302", "\065\097\080\166\044\136\231\064" ; 2, 11, 16, 167, 229, "02:11:16.167229", "\242\013\133\207\042\196\190\064" ; 16, 10, 44, 550, 609, "16:10:44.550609", "\253\195\150\158\145\112\236\064" ; 8, 36, 42, 700, 606, "08:36:42.700606", "\089\140\186\214\172\070\222\064" ; 11, 33, 47, 481, 583, "11:33:47.481583", "\106\192\032\105\111\083\228\064" ; 16, 50, 22, 332, 982, "16:50:22.332982", "\005\222\201\167\202\153\237\064" ; 11, 26, 39, 358, 179, "11:26:39.358179", "\100\206\051\118\235\029\228\064" ; 5, 8, 23, 655, 819, "05:08:23.655819", "\070\065\240\248\233\017\210\064" ; 14, 33, 31, 605, 859, "14:33:31.605859", "\224\105\050\099\115\151\233\064" ; 15, 32, 14, 569, 768, "15:32:14.569768", "\202\025\138\059\210\079\235\064" ; 18, 11, 3, 894, 770, "18:11:03.894770", "\238\177\244\161\252\246\239\064" ; 5, 16, 6, 567, 426, "05:16:06.567426", "\057\036\181\080\164\133\210\064" ; 20, 59, 34, 407, 815, "20:59:34.407815", "\126\005\105\134\102\115\242\064" ; 7, 53, 33, 333, 91, "07:53:33.333091", "\230\233\092\081\085\191\219\064" ; 0, 52, 33, 910, 588, "00:52:33.910588", "\066\032\151\056\210\163\168\064" ; 12, 29, 36, 392, 331, "12:29:36.392331", "\199\189\249\141\012\246\229\064" ; 18, 34, 45, 860, 679, "18:34:45.860679", "\214\087\087\197\093\084\240\064" ; 7, 7, 55, 508, 170, "07:07:55.508170", "\180\118\219\133\224\018\217\064" ; 12, 56, 51, 409, 583, "12:56:51.409583", "\192\206\077\027\109\194\230\064" ; 18, 7, 48, 842, 431, "18:07:48.842431", "\068\219\049\245\154\222\239\064" ; 1, 41, 52, 821, 422, "01:41:52.821422", "\055\082\182\072\210\224\183\064" ; 17, 22, 38, 40, 815, "17:22:38.040815", "\070\066\091\078\193\139\238\064" ; 19, 3, 14, 106, 401, "19:03:14.106401", "\244\136\209\179\033\191\240\064" ; 18, 28, 52, 10, 260, "18:28:52.010260", "\199\099\006\042\064\062\240\064" ; 23, 6, 4, 87, 903, "23:06:04.087903", "\227\249\012\104\193\077\244\064" ; 20, 35, 16, 930, 653, "20:35:16.930653", "\110\102\244\227\078\024\242\064" ; 8, 3, 41, 162, 890, "08:03:41.162890", "\182\045\202\108\074\087\220\064" ; 20, 21, 32, 30, 843, "20:21:32.030843", "\197\058\085\126\192\228\241\064" ; 4, 57, 6, 570, 94, "04:57:06.570094", "\105\139\107\124\164\104\209\064" ; 19, 28, 33, 625, 262, "19:28:33.625262", "\023\186\018\001\026\030\241\064" ; 21, 11, 30, 483, 225, "21:11:30.483225", "\057\035\074\187\039\160\242\064" ; 14, 16, 47, 559, 993, "14:16:47.559993", "\160\112\118\235\241\025\233\064" ; 15, 0, 0, 981, 186, "15:00:00.981186", "\169\046\224\101\031\094\234\064" ; 22, 4, 7, 784, 947, "22:04:07.784947", "\225\149\036\143\124\101\243\064" ; 14, 54, 15, 590, 16, "14:54:15.590016", "\003\060\105\225\242\050\234\064" ; 12, 33, 7, 620, 244, "12:33:07.620244", "\242\241\009\217\115\016\230\064" ; 16, 52, 56, 681, 332, "16:52:56.681332", "\055\196\120\205\021\173\237\064" ; 8, 47, 0, 382, 956, "08:47:00.382956", "\244\225\089\130\024\225\222\064" ; 14, 9, 53, 363, 743, "14:09:53.363743", "\036\092\200\163\043\230\232\064" ; 20, 21, 57, 159, 86, "20:21:57.159086", "\244\194\157\139\082\230\241\064" ; 9, 7, 55, 657, 291, "09:07:55.657291", "\158\034\135\008\117\013\224\064" ; 16, 7, 28, 223, 61, "16:07:28.223061", "\128\210\080\035\007\088\236\064" ; 22, 42, 24, 538, 166, "22:42:24.538166", "\157\243\083\156\008\245\243\064" ; 0, 25, 20, 578, 217, "00:25:20.578217", "\247\003\030\024\080\194\151\064" ; 8, 37, 25, 339, 497, "08:37:25.339497", "\006\160\081\186\085\081\222\064" ; 4, 39, 17, 579, 853, "04:39:17.579853", "\224\193\079\028\101\093\208\064" ; 3, 9, 16, 389, 817, "03:09:16.389817", "\054\001\134\229\049\046\198\064" ; 17, 15, 42, 260, 495, "17:15:42.260495", "\057\156\249\085\200\087\238\064" ; 18, 52, 31, 390, 15, "18:52:31.390015", "\095\094\128\061\246\150\240\064" ; 3, 17, 55, 81, 244, "03:17:55.081244", "\128\017\052\102\138\049\199\064" ; 17, 52, 10, 951, 438, "17:52:10.951438", "\198\026\046\114\094\105\239\064" ; 20, 53, 24, 925, 549, "20:53:24.925549", "\222\119\012\207\078\092\242\064" ; 0, 28, 2, 996, 572, "00:28:02.996572", "\112\208\094\125\252\075\154\064" ; 10, 29, 38, 479, 884, "10:29:38.479884", "\188\176\053\091\079\114\226\064" ; 15, 26, 32, 360, 765, "15:26:32.360765", "\145\010\099\139\011\037\235\064" ; 6, 13, 27, 574, 393, "06:13:27.574393", "\131\219\218\194\228\225\213\064" ; 23, 9, 54, 40, 585, "23:09:54.040585", "\251\116\060\166\032\092\244\064" ; 7, 50, 26, 856, 208, "07:50:26.856208", "\165\163\028\204\182\144\219\064" ; 15, 58, 40, 647, 651, "15:58:40.647651", "\007\151\142\185\020\022\236\064" ; 7, 4, 23, 350, 201, "07:04:23.350201", "\129\116\177\105\214\221\216\064" ; 20, 41, 0, 640, 870, "20:41:00.640870", "\176\230\000\065\202\045\242\064" ; 5, 12, 50, 798, 22, "05:12:50.798022", "\223\221\202\018\179\084\210\064" ; 7, 11, 4, 45, 800, "07:11:04.045800", "\138\031\099\238\002\066\217\064" ; 19, 44, 4, 942, 509, "19:44:04.942509", "\051\081\132\020\079\088\241\064" ; 0, 17, 2, 618, 423, "00:17:02.618423", "\193\000\194\135\242\244\143\064" ; 16, 38, 29, 855, 573, "16:38:29.855573", "\203\160\218\096\187\064\237\064" ; 1, 1, 7, 236, 16, "01:01:07.236016", "\170\210\022\215\120\166\172\064" ; 8, 40, 49, 4, 118, "08:40:49.004118", "\213\036\120\067\064\132\222\064" ; 7, 48, 57, 83, 41, "07:48:57.083041", "\206\050\139\080\069\122\219\064" ; 21, 5, 48, 492, 591, "21:05:48.492591", "\181\025\167\225\199\138\242\064" ; 13, 27, 30, 783, 944, "13:27:30.783944", "\061\186\017\022\089\168\231\064" ; 19, 26, 26, 46, 822, "19:26:26.046822", "\236\108\200\191\032\022\241\064" ; 13, 54, 34, 139, 440, "13:54:34.139440", "\249\223\074\118\068\115\232\064" ; 8, 12, 6, 189, 698, "08:12:06.189698", "\135\020\003\036\140\213\220\064" ; 21, 16, 14, 240, 798, "21:16:14.240798", "\239\000\079\218\227\177\242\064" ; 5, 32, 50, 832, 834, "05:32:50.832834", "\063\250\038\077\181\128\211\064" ; 3, 24, 41, 875, 811, "03:24:41.875811", "\061\041\147\026\240\252\199\064" ; 1, 37, 37, 749, 127, "01:37:37.749127", "\141\125\201\198\191\225\182\064" ; 13, 6, 35, 160, 262, "13:06:35.160262", "\026\198\221\032\101\011\231\064" ; 19, 21, 3, 550, 829, "19:21:03.550829", "\203\017\050\208\248\001\241\064" ; 2, 50, 32, 616, 961, "02:50:32.616961", "\244\250\147\248\078\252\195\064" ; 21, 41, 26, 169, 99, "21:41:26.169099", "\044\039\161\180\098\016\243\064" ; 9, 30, 46, 953, 396, "09:30:46.953396", "\005\084\056\130\222\184\224\064" ; 3, 11, 43, 710, 81, "03:11:43.710081", "\065\040\239\227\218\119\198\064" ; 13, 6, 36, 105, 423, "13:06:36.105423", "\040\014\160\095\131\011\231\064" ; 19, 48, 20, 958, 38, "19:48:20.958038", "\101\167\031\084\079\104\241\064" ; 23, 23, 25, 680, 852, "23:23:25.680852", "\022\017\197\228\218\142\244\064" ; 22, 53, 27, 258, 278, "22:53:27.258278", "\181\028\232\033\116\030\244\064" ; 19, 31, 44, 899, 413, "19:31:44.899413", "\202\226\254\099\014\042\241\064" ; 4, 35, 8, 655, 880, "04:35:08.655880", "\134\027\240\249\041\031\208\064" ; 15, 10, 56, 798, 751, "15:10:56.798751", "\213\065\094\143\025\176\234\064" ; 5, 58, 24, 48, 388, "05:58:24.048388", "\097\251\201\024\003\000\213\064" ; 23, 24, 9, 356, 213, "23:24:09.356213", "\023\103\012\179\149\145\244\064" ; 0, 46, 8, 749, 174, "00:46:08.749174", "\006\010\188\147\127\161\165\064" ; 17, 24, 23, 857, 997, "17:24:23.857997", "\227\031\182\116\251\152\238\064" ; 6, 57, 57, 191, 918, "06:57:57.191918", "\097\111\098\072\076\125\216\064" ; 7, 6, 1, 538, 522, "07:06:01.538522", "\139\250\036\119\098\246\216\064" ; 7, 40, 33, 868, 303, "07:40:33.868303", "\001\191\070\146\119\252\218\064" ; 1, 3, 55, 80, 576, "01:03:55.080576", "\175\233\065\065\041\246\173\064" ; 23, 34, 11, 231, 497, "23:34:11.231497", "\194\050\054\180\051\183\244\064" ; 11, 42, 19, 323, 317, "11:42:19.323317", "\167\228\156\088\106\147\228\064" ; 11, 48, 9, 517, 846, "11:48:09.517846", "\076\198\049\146\048\191\228\064" ; 1, 45, 38, 490, 204, "01:45:38.490204", "\094\100\002\126\125\194\184\064" ; 5, 57, 14, 491, 815, "05:57:14.491815", "\044\159\229\121\159\238\212\064" ; 16, 34, 3, 154, 742, "16:34:03.154742", "\170\126\165\243\100\031\237\064" ; 7, 23, 37, 205, 287, "07:23:37.205287", "\211\021\108\035\077\254\217\064" ; 10, 38, 2, 335, 219, "10:38:02.335219", "\064\050\029\186\074\177\226\064" ; 4, 38, 33, 451, 101, "04:38:33.451101", "\141\186\214\222\092\082\208\064" ; 12, 3, 36, 336, 353, "12:03:36.336353", "\222\093\103\195\010\051\229\064" ; 5, 55, 16, 600, 219, "05:55:16.600219", "\220\243\252\105\038\209\212\064" ; 21, 19, 54, 848, 695, "21:19:54.848695", "\084\053\065\148\173\191\242\064" ; 9, 30, 51, 733, 361, "09:30:51.733361", "\229\124\177\119\119\185\224\064" ; 13, 18, 27, 877, 886, "13:18:27.877886", "\116\097\164\023\124\100\231\064" ; 14, 10, 58, 770, 843, "14:10:58.770843", "\107\240\190\170\088\238\232\064" ; 4, 47, 34, 303, 422, "04:47:34.303422", "\185\027\068\107\147\217\208\064" ; 2, 4, 22, 547, 666, "02:04:22.547666", "\033\199\214\051\140\038\189\064" ; 6, 30, 54, 459, 902, "06:30:54.459902", "\087\204\008\111\157\231\214\064" ; 1, 14, 36, 942, 31, "01:14:36.942031", "\209\144\241\040\241\124\177\064" ; 5, 3, 1, 63, 870, "05:03:01.063870", "\076\050\114\022\068\193\209\064" ; 18, 54, 46, 757, 335, "18:54:46.757335", "\018\078\011\030\108\159\240\064" ; 15, 54, 55, 220, 211, "15:54:55.220211", "\103\240\247\011\231\249\235\064" ; 0, 36, 45, 441, 94, "00:36:45.441094", "\236\160\018\215\225\058\161\064" ; 9, 20, 4, 8, 423, "09:20:04.008423", "\177\079\000\069\128\104\224\064" ; 12, 5, 57, 853, 151, "12:05:57.853151", "\114\083\003\077\187\068\229\064" ; 1, 39, 56, 782, 119, "01:39:56.782119", "\149\102\243\056\200\108\183\064" ; 4, 9, 40, 639, 752, "04:09:40.639752", "\198\190\100\227\081\066\205\064" ; 10, 31, 59, 818, 679, "10:31:59.818679", "\093\077\158\050\250\131\226\064" ; 18, 40, 24, 181, 815, "18:40:24.181815", "\111\216\182\232\130\105\240\064" ; 23, 57, 53, 746, 216, "23:57:53.746216", "\060\048\128\240\027\016\245\064" ; 17, 29, 24, 396, 964, "17:29:24.396964", "\182\216\237\179\140\190\238\064" ; 0, 31, 53, 566, 423, "00:31:53.566423", "\207\018\100\004\068\230\157\064" ; 4, 15, 7, 222, 661, "04:15:07.222661", "\140\216\039\128\156\229\205\064" ; 13, 1, 27, 689, 609, "13:01:27.689609", "\193\228\070\017\246\228\230\064" ; 14, 58, 25, 812, 602, "14:58:25.812602", "\213\232\213\000\058\082\234\064" ; 23, 16, 6, 54, 806, "23:16:06.054806", "\154\065\124\224\096\115\244\064" ; 0, 34, 8, 69, 288, "00:34:08.069288", "\003\124\183\121\035\000\160\064" ; 8, 44, 31, 397, 563, "08:44:31.397563", "\199\020\172\113\217\187\222\064" ; 13, 1, 18, 663, 309, "13:01:18.663309", "\197\203\211\057\213\227\230\064" ; 16, 48, 16, 686, 463, "16:48:16.686463", "\221\064\129\247\021\138\237\064" ; 9, 58, 58, 330, 322, "09:58:58.330322", "\101\113\255\145\074\140\225\064" ; 17, 13, 13, 83, 195, "17:13:13.083195", "\134\143\136\169\034\069\238\064" ; 12, 44, 29, 374, 195, "12:44:29.374195", "\235\202\103\249\171\101\230\064" ; 12, 26, 8, 571, 135, "12:26:08.571135", "\084\232\188\070\018\220\229\064" ; 14, 53, 21, 389, 813, "14:53:21.389813", "\210\028\089\121\044\044\234\064" ; 10, 32, 58, 3, 526, "10:32:58.003526", "\214\142\226\028\064\139\226\064" ; 19, 2, 2, 172, 974, "19:02:02.172974", "\145\098\128\196\162\186\240\064" ; 16, 37, 49, 282, 995, "16:37:49.282995", "\190\135\075\014\169\059\237\064" ; 16, 35, 54, 843, 228, "16:35:54.843228", "\098\073\185\251\090\045\237\064" ; 4, 22, 9, 651, 220, "04:22:09.651220", "\064\077\045\091\211\184\206\064" ; 2, 5, 57, 652, 303, "02:05:57.652303", "\021\084\084\253\166\133\189\064" ; 9, 19, 13, 497, 990, "09:19:13.497990", "\120\185\136\239\047\098\224\064" ; 14, 3, 8, 976, 907, "14:03:08.976907", "\008\120\210\066\159\179\232\064" ; 21, 50, 11, 920, 670, "21:50:11.920670", "\070\119\016\187\062\049\243\064" ; 7, 24, 28, 176, 291, "07:24:28.176291", "\229\011\090\072\011\011\218\064" ; 18, 43, 59, 755, 572, "18:43:59.755572", "\093\170\210\022\252\118\240\064" ; 23, 42, 32, 576, 625, "23:42:32.576625", "\209\034\219\057\137\214\244\064" ; 6, 0, 33, 626, 844, "06:00:33.626844", "\236\075\054\030\104\032\213\064" ; 14, 15, 51, 595, 615, "14:15:51.595615", "\064\048\071\015\243\018\233\064" ; 13, 25, 2, 231, 322, "13:25:02.231322", "\027\101\253\102\199\149\231\064" ; 1, 10, 23, 980, 625, "01:10:23.980625", "\163\112\061\010\251\127\176\064" ; 21, 29, 36, 40, 205, "21:29:36.040205", "\130\255\173\164\000\228\242\064" ; 14, 17, 12, 627, 816, "14:17:12.627816", "\125\148\017\023\020\029\233\064" ; 1, 44, 49, 644, 591, "01:44:49.644591", "\076\112\234\003\165\145\184\064" ; 1, 9, 15, 739, 148, "01:09:15.739148", "\231\166\205\056\189\059\176\064" ; 5, 33, 53, 684, 683, "05:33:53.684683", "\072\165\216\209\107\144\211\064" ; 7, 29, 57, 728, 977, "07:29:57.728977", "\162\037\143\167\110\093\218\064" ; 0, 51, 55, 970, 425, "00:51:55.970425", "\113\172\139\219\240\087\168\064" ; 0, 44, 27, 612, 257, "00:44:27.612257", "\127\223\191\121\057\215\164\064" ; 17, 38, 36, 883, 888, "17:38:36.883888", "\171\124\207\072\156\003\239\064" ; 16, 40, 29, 721, 23, "16:40:29.721023", "\149\211\158\018\183\079\237\064" ; 20, 0, 5, 62, 8, "20:00:05.062008", "\194\025\252\253\080\148\241\064" ; 11, 19, 34, 667, 504, "11:19:34.667504", "\063\089\049\092\213\232\227\064" ; 10, 9, 5, 356, 68, "10:09:05.356068", "\229\183\232\100\043\216\225\064" ; 9, 39, 35, 435, 378, "09:39:35.435378", "\236\215\157\238\237\250\224\064" ; 14, 44, 38, 651, 528, "14:44:38.651528", "\141\063\081\217\212\234\233\064" ; 20, 7, 11, 465, 623, "20:07:11.465623", "\084\026\049\115\247\174\241\064" ; 5, 21, 54, 746, 214, "05:21:54.746214", "\116\093\248\193\175\220\210\064" ; 5, 2, 28, 785, 454, "05:02:28.785454", "\161\218\224\068\050\185\209\064" ; 0, 7, 13, 976, 814, "00:07:13.976814", "\102\132\183\007\161\031\123\064" ; 12, 30, 52, 986, 584, "12:30:52.986584", "\216\155\024\146\159\255\229\064" ; 23, 0, 9, 890, 333, "23:00:09.890333", "\217\208\205\062\158\055\244\064" ; 16, 47, 28, 730, 966, "16:47:28.730966", "\016\207\018\100\023\132\237\064" ; 6, 25, 38, 87, 370, "06:25:38.087370", "\042\087\120\151\133\152\214\064" ; 8, 12, 32, 529, 536, "08:12:32.529536", "\131\246\234\227\033\220\220\064" ; 22, 58, 13, 464, 522, "22:58:13.464522", "\229\158\174\110\087\048\244\064" ; 17, 5, 45, 419, 982, "17:05:45.419982", "\093\023\126\112\045\013\238\064" ; 14, 8, 20, 460, 395, "14:08:20.460395", "\136\075\142\187\142\218\232\064" ; 12, 20, 48, 989, 163, "12:20:48.989163", "\237\041\057\167\031\180\229\064" ; 5, 56, 46, 391, 774, "05:56:46.391774", "\091\065\211\018\153\231\212\064" ; 8, 24, 55, 829, 132, "08:24:55.829132", "\005\170\127\016\245\149\221\064" ; 8, 11, 21, 883, 778, "08:11:21.883778", "\188\153\209\143\120\202\220\064" ; 19, 0, 51, 800, 795, "19:00:51.800795", "\253\106\014\208\060\182\240\064" ; 6, 22, 17, 146, 408, "06:22:17.146408", "\248\168\191\094\073\102\214\064" ; 5, 43, 4, 350, 421, "05:43:04.350421", "\181\051\076\109\022\026\212\064" ; 19, 12, 9, 954, 917, "19:12:09.954917", "\086\012\087\071\159\224\240\064" ; 3, 18, 32, 484, 587, "03:18:32.484587", "\137\098\242\006\062\068\199\064" ; 11, 44, 35, 172, 48, "11:44:35.172048", "\171\206\106\129\101\164\228\064" ; 23, 9, 19, 453, 935, "23:09:19.453935", "\184\088\081\067\247\089\244\064" ; 4, 17, 42, 822, 24, "04:17:42.822024", "\068\026\021\056\105\051\206\064" ; 4, 45, 33, 548, 520, "04:45:33.548520", "\077\161\243\026\099\187\208\064" ; 21, 38, 35, 594, 936, "21:38:35.594936", "\115\156\219\132\185\005\243\064" ; 15, 8, 51, 181, 906, "15:08:51.181906", "\030\136\044\210\101\160\234\064" ; 12, 27, 9, 619, 514, "12:27:09.619514", "\045\006\015\211\179\227\229\064" ; 16, 53, 12, 237, 270, "16:53:12.237270", "\074\065\183\151\007\175\237\064" ; 22, 1, 43, 68, 975, "22:01:43.068975", "\148\135\133\026\113\092\243\064" ; 17, 48, 58, 912, 30, "17:48:58.912030", "\223\137\089\047\093\081\239\064" ; 18, 10, 16, 772, 131, "18:10:16.772131", "\039\018\076\181\024\241\239\064" ; 14, 18, 23, 345, 925, "14:18:23.345925", "\060\078\209\017\235\037\233\064" ; 20, 23, 36, 490, 796, "20:23:36.490796", "\016\232\076\218\135\236\241\064" ; 11, 2, 27, 740, 298, "11:02:27.740298", "\105\110\133\176\119\104\227\064" ; 10, 36, 13, 392, 53, "10:36:13.392053", "\170\187\178\139\172\163\226\064" ; 5, 4, 30, 466, 719, "05:04:30.466719", "\091\094\185\222\157\215\209\064" ; 3, 0, 10, 479, 243, "03:00:10.479243", "\235\169\213\087\061\029\197\064" ; 2, 5, 11, 305, 582, "02:05:11.305582", "\063\056\159\058\078\087\189\064" ; 21, 35, 3, 314, 864, "21:35:03.314864", "\107\213\174\009\117\248\242\064" ; 17, 16, 53, 558, 730, "17:16:53.558730", "\169\188\029\225\177\096\238\064" ; 1, 48, 19, 228, 74, "01:48:19.228074", "\017\195\014\099\058\099\185\064" ; 13, 27, 48, 527, 718, "13:27:48.527718", "\241\219\016\227\144\170\231\064" ; 8, 46, 56, 748, 324, "08:46:56.748324", "\180\088\138\228\047\224\222\064" ; 8, 22, 13, 82, 818, "08:22:13.082818", "\097\222\227\076\069\109\221\064" ; 16, 39, 41, 909, 942, "16:39:41.909942", "\104\175\062\030\189\073\237\064" ; 14, 0, 5, 866, 146, "14:00:05.866146", "\242\208\119\183\187\156\232\064" ; 21, 10, 44, 526, 994, "21:10:44.526994", "\179\066\145\110\072\157\242\064" ; 14, 7, 12, 628, 81, "14:07:12.628081", "\071\083\061\025\020\210\232\064" ; 0, 26, 6, 970, 279, "00:26:06.970279", "\252\115\209\144\225\123\152\064" ; 3, 20, 25, 74, 365, "03:20:25.074365", "\124\213\202\132\137\124\199\064" ; 12, 42, 54, 620, 503, "12:42:54.620503", "\131\027\041\219\211\089\230\064" ; 0, 55, 42, 465, 439, "00:55:42.465439", "\145\070\005\078\238\028\170\064" ; 0, 38, 15, 200, 620, "00:38:15.200620", "\216\037\170\183\102\238\161\064" ; 20, 39, 48, 225, 921, "20:39:48.225921", "\168\086\095\157\067\041\242\064" ; 17, 39, 31, 166, 952, "17:39:31.166952", "\128\184\171\087\101\010\239\064" ; 16, 51, 12, 844, 765, "16:51:12.844765", "\249\155\080\008\027\160\237\064" ; 1, 55, 33, 699, 920, "01:55:33.699920", "\209\005\245\045\179\021\187\064" ; 10, 40, 5, 431, 475, "10:40:05.431475", "\193\168\164\206\173\192\226\064" ; 9, 25, 5, 483, 383, "09:25:05.483383", "\014\160\223\119\047\142\224\064" ; 14, 1, 52, 775, 223, "14:01:52.775223", "\004\119\160\206\024\170\232\064" ; 9, 53, 26, 920, 924, "09:53:26.920924", "\195\155\053\120\221\098\225\064" ; 20, 20, 44, 506, 794, "20:20:44.506794", "\125\006\212\027\200\225\241\064" ; 14, 6, 42, 138, 789, "14:06:42.138789", "\001\161\245\112\068\206\232\064" ; 8, 46, 3, 492, 646, "08:46:03.492646", "\160\022\131\135\223\210\222\064" ; 8, 12, 24, 180, 507, "08:12:24.180507", "\109\059\109\141\011\218\220\064" ; 6, 39, 0, 415, 961, "06:39:00.415961", "\219\226\026\159\026\097\215\064" ; 9, 9, 51, 925, 962, "09:09:51.925962", "\107\015\123\161\253\027\224\064" ; 0, 41, 47, 585, 202, "00:41:47.585202", "\028\183\152\159\043\151\163\064" ; 8, 10, 7, 552, 951, "08:10:07.552951", "\083\151\140\099\227\183\220\064" ; 15, 9, 37, 819, 810, "15:09:37.819810", "\094\046\226\059\058\166\234\064" ; 22, 31, 27, 357, 627, "22:31:27.357627", "\211\022\215\184\245\203\243\064" ; 11, 23, 15, 505, 371, "11:23:15.505371", "\171\205\255\043\112\004\228\064" ; 22, 53, 3, 740, 150, "22:53:03.740150", "\195\134\167\215\251\028\244\064" ; 11, 54, 27, 341, 59, "11:54:27.341059", "\096\144\244\233\106\238\228\064" ; 6, 50, 45, 634, 438, "06:50:45.634438", "\085\215\161\154\104\017\216\064" ; 14, 37, 51, 622, 520, "14:37:51.622520", "\036\016\175\235\243\183\233\064" ; 16, 20, 20, 830, 646, "16:20:20.830646", "\146\235\166\148\154\184\236\064" ; 21, 6, 47, 617, 97, "21:06:47.617097", "\151\026\161\223\121\142\242\064" ; 21, 11, 33, 889, 829, "21:11:33.889829", "\096\085\189\060\094\160\242\064" ; 16, 19, 25, 755, 156, "16:19:25.755156", "\108\234\060\042\184\177\236\064" ; 15, 56, 53, 718, 326, "15:56:53.718326", "\188\206\134\252\182\008\236\064" ; 18, 6, 40, 919, 312, "18:06:40.919312", "\218\255\000\107\029\214\239\064" ; 7, 26, 14, 72, 524, "07:26:14.072524", "\011\180\059\164\132\037\218\064" ; 10, 0, 52, 665, 922, "10:00:52.665922", "\118\167\059\079\149\154\225\064" ; 6, 24, 6, 844, 582, "06:24:06.844582", "\051\169\161\013\182\129\214\064" ; 9, 0, 15, 958, 882, "09:00:15.958882", "\174\155\082\094\253\167\223\064" ; 13, 2, 37, 459, 782, "13:02:37.459782", "\170\189\136\182\174\237\230\064" ; 0, 29, 29, 219, 869, "00:29:29.219869", "\158\209\086\037\225\164\155\064" ; 6, 20, 11, 188, 710, "06:20:11.188710", "\155\027\211\019\204\070\214\064" ; 9, 53, 48, 198, 358, "09:53:48.198358", "\092\224\242\088\134\101\225\064" ; 1, 3, 39, 421, 962, "01:03:39.421962", "\079\060\103\011\216\214\173\064" ; 0, 22, 10, 25, 982, "00:22:10.025982", "\036\129\006\155\026\200\148\064" ; 21, 41, 40, 726, 948, "21:41:40.726948", "\222\057\148\161\075\017\243\064" ; 12, 4, 14, 770, 336, "12:04:14.770336", "\221\174\151\166\216\055\229\064" ; 12, 2, 52, 153, 881, "12:02:52.153881", "\207\216\151\236\132\045\229\064" ; 11, 58, 18, 798, 191, "11:58:18.798191", "\031\218\199\138\089\011\229\064" ; 19, 43, 30, 67, 748, "19:43:30.067748", "\070\237\126\021\033\086\241\064" ; 8, 51, 2, 57, 71, "08:51:02.057071", "\163\031\013\167\131\029\223\064" ; 0, 1, 46, 966, 209, "00:01:46.966209", "\116\006\070\094\214\189\090\064" ; 18, 52, 42, 210, 103, "18:52:42.210103", "\157\246\148\092\163\151\240\064" ; 9, 22, 22, 315, 197, "09:22:22.315197", "\218\004\024\022\202\121\224\064" ; 8, 50, 24, 724, 335, "08:50:24.724335", "\022\048\129\091\046\020\223\064" ; 13, 39, 9, 900, 160, "13:39:09.900160", "\038\088\028\206\188\255\231\064" ; 18, 43, 17, 159, 11, "18:43:17.159011", "\075\030\079\139\082\116\240\064" ; 5, 12, 27, 583, 285, "05:12:27.583285", "\207\155\138\084\229\078\210\064" ; 10, 21, 42, 934, 745, "10:21:42.934745", "\163\088\110\233\221\054\226\064" ; 14, 13, 9, 227, 516, "14:13:09.227516", "\106\162\207\071\167\254\232\064" ; 4, 52, 45, 826, 766, "04:52:45.826766", "\221\240\187\233\116\039\209\064" ; 17, 3, 32, 249, 109, "17:03:32.249109", "\005\112\179\248\135\252\237\064" ; 17, 55, 16, 724, 540, "17:55:16.724540", "\149\130\110\047\151\128\239\064" ; 22, 42, 29, 222, 458, "22:42:29.222458", "\171\030\048\143\083\245\243\064" ; 5, 21, 16, 611, 19, "05:21:16.611019", "\143\111\239\026\039\211\210\064" ; 1, 32, 1, 289, 666, "01:32:01.289666", "\195\012\141\039\074\145\181\064" ; 13, 53, 2, 305, 796, "13:53:02.305796", "\104\177\020\201\201\103\232\064" ; 18, 13, 24, 770, 314, "18:13:24.770314", "\219\197\052\083\076\004\240\064" ; 10, 14, 52, 779, 910, "10:14:52.779910", "\251\208\005\245\152\003\226\064" ; 15, 21, 20, 85, 316, "15:21:20.085316", "\186\158\232\186\002\254\234\064" ; 17, 45, 23, 21, 748, "17:45:23.021748", "\152\220\040\178\096\054\239\064" ; 7, 38, 13, 964, 152, "07:38:13.964152", "\024\151\170\180\125\217\218\064" ; 20, 0, 24, 76, 329, "20:00:24.076329", "\236\193\164\056\129\149\241\064" ; 14, 42, 3, 732, 658, "14:42:03.732658", "\165\048\239\113\119\215\233\064" ; 23, 34, 34, 147, 348, "23:34:34.147348", "\146\147\137\091\162\184\244\064" ; 23, 20, 18, 627, 30, "23:20:18.627030", "\249\155\080\008\042\131\244\064" ; 15, 54, 29, 520, 167, "15:54:29.520167", "\174\067\053\165\176\246\235\064" ; 4, 32, 38, 504, 796, "04:32:38.504796", "\148\195\039\157\064\243\207\064" ; 2, 39, 3, 392, 738, "02:39:03.392738", "\243\032\061\069\178\163\194\064" ; 2, 41, 56, 44, 14, "02:41:56.044014", "\072\049\064\162\005\250\194\064" ; 0, 4, 44, 525, 852, "00:04:44.525852", "\148\104\201\227\105\200\113\064" ; 5, 59, 44, 688, 949, "05:59:44.688949", "\231\139\189\023\044\020\213\064" ; 4, 6, 13, 342, 110, "04:06:13.342110", "\210\174\066\202\171\218\204\064" ; 19, 43, 32, 206, 995, "19:43:32.206995", "\055\253\217\079\067\086\241\064" ; 4, 59, 28, 105, 825, "04:59:28.105825", "\134\056\214\197\006\140\209\064" ; 16, 21, 19, 602, 317, "16:21:19.602317", "\026\077\046\070\243\191\236\064" ; 14, 2, 57, 922, 73, "14:02:57.922073", "\113\060\159\129\061\178\232\064" ; 10, 36, 26, 511, 178, "10:36:26.511178", "\014\247\145\091\080\165\226\064" ; 22, 20, 11, 305, 187, "22:20:11.305187", "\130\195\011\226\180\161\243\064" ; 2, 29, 14, 361, 846, "02:29:14.361846", "\025\064\248\080\046\125\193\064" ; 6, 30, 49, 296, 501, "06:30:49.296501", "\142\084\223\249\082\230\214\064" ; 6, 35, 55, 399, 650, "06:35:55.399650", "\247\151\221\147\217\050\215\064" ; 5, 27, 21, 192, 90, "05:27:21.192090", "\249\218\051\075\076\046\211\064" ; 2, 57, 1, 556, 651, "02:57:01.556651", "\037\008\087\064\199\190\196\064" ; 17, 11, 10, 498, 913, "17:11:10.498913", "\082\101\024\247\207\053\238\064" ; 0, 56, 7, 589, 899, "00:56:07.589899", "\227\225\061\007\046\079\170\064" ; 15, 4, 59, 615, 239, "15:04:59.615239", "\007\179\009\176\115\131\234\064" ; 17, 44, 47, 313, 554, "17:44:47.313554", "\241\101\162\008\234\049\239\064" ; 17, 37, 57, 358, 216, "17:37:57.358216", "\157\102\129\118\171\254\238\064" ; 18, 3, 28, 580, 547, "18:03:28.580547", "\090\077\215\147\018\190\239\064" ; 22, 26, 43, 315, 209, "22:26:43.315209", "\167\151\024\011\053\186\243\064" ; 21, 36, 32, 793, 865, "21:36:32.793865", "\071\201\171\179\012\254\242\064" ; 11, 41, 23, 502, 610, "11:41:23.502610", "\021\145\097\021\112\140\228\064" ; 22, 38, 40, 451, 268, "22:38:40.451268", "\092\203\100\056\007\231\243\064" ; 3, 23, 12, 779, 572, "03:23:12.779572", "\113\234\003\201\099\208\199\064" ; 14, 9, 12, 346, 103, "14:09:12.346103", "\065\153\070\019\011\225\232\064" ; 19, 29, 13, 660, 509, "19:29:13.660509", "\156\226\113\145\154\032\241\064" ; 21, 10, 58, 60, 666, "21:10:58.060666", "\096\233\124\248\032\158\242\064" ; 16, 40, 40, 684, 657, "16:40:40.684657", "\255\203\181\232\021\081\237\064" ; 14, 48, 22, 77, 67, "14:48:22.077067", "\147\054\085\119\194\006\234\064" ; 8, 58, 29, 975, 44, "08:58:29.975044", "\010\243\030\103\126\141\223\064" ; 9, 22, 26, 525, 57, "09:22:26.525057", "\113\086\068\205\080\122\224\064" ; 23, 27, 39, 93, 827, "23:27:39.093827", "\135\189\080\128\177\158\244\064" ; 8, 10, 29, 599, 638, "08:10:29.599638", "\220\015\120\096\102\189\220\064" ; 16, 20, 46, 878, 621, "16:20:46.878621", "\146\201\169\029\220\187\236\064" ; 0, 33, 30, 503, 72, "00:33:30.503072", "\034\110\078\037\003\106\159\064" ; 14, 13, 59, 54, 523, "14:13:59.054523", "\188\004\167\190\225\004\233\064" ; 1, 43, 30, 561, 530, "01:43:30.561530", "\185\025\110\192\143\066\184\064" ; 15, 31, 38, 288, 488, "15:31:38.288488", "\169\047\075\059\073\075\235\064" ; 4, 21, 48, 93, 756, "04:21:48.093756", "\231\084\050\000\012\174\206\064" ; 1, 54, 26, 57, 450, "01:54:26.057450", "\039\015\011\181\014\210\186\064" ; 1, 9, 9, 156, 305, "01:09:09.156305", "\051\191\154\003\040\053\176\064" ; 13, 5, 25, 799, 697, "13:05:25.799697", "\183\041\030\151\185\002\231\064" ; 22, 57, 58, 505, 250, "22:57:58.505250", "\037\006\129\021\104\047\244\064" ; 20, 10, 37, 546, 693, "20:10:37.546693", "\191\040\065\191\216\187\241\064" ; 18, 33, 12, 311, 450, "18:33:12.311450", "\198\254\178\251\132\078\240\064" ; 18, 26, 25, 667, 726, "18:26:25.667726", "\075\117\001\175\026\053\240\064" ; 4, 8, 59, 769, 831, "04:08:59.769831", "\057\124\210\137\226\045\205\064" ; 7, 12, 35, 502, 233, "07:12:35.502233", "\126\225\149\036\224\088\217\064" ; 5, 26, 25, 535, 507, "05:26:25.535507", "\242\038\191\069\098\032\211\064" ; 11, 32, 26, 931, 164, "11:32:26.931164", "\230\113\024\204\093\073\228\064" ; 20, 9, 4, 439, 362, "20:09:04.439362", "\210\114\160\007\007\182\241\064" ; 4, 38, 8, 13, 31, "04:38:08.013031", "\181\249\127\213\000\076\208\064" ; 23, 0, 32, 695, 526, "23:00:32.695526", "\249\222\223\032\011\057\244\064" ; 11, 49, 14, 197, 28, "11:49:14.197028", "\013\170\013\078\070\199\228\064" ; 13, 9, 54, 410, 840, "13:09:54.410840", "\125\237\153\037\077\036\231\064" ; 3, 11, 0, 917, 602, "03:11:00.917602", "\095\122\251\115\117\098\198\064" ; 0, 8, 59, 667, 357, "00:08:59.667357", "\014\078\068\191\086\221\128\064" ; 1, 29, 7, 134, 583, "01:29:07.134583", "\153\015\008\116\034\227\180\064" ; 19, 4, 48, 775, 274, "19:04:48.775274", "\183\181\133\103\012\197\240\064" ; 23, 41, 3, 869, 667, "23:41:03.869667", "\183\241\039\234\253\208\244\064" ; 7, 38, 12, 336, 720, "07:38:12.336720", "\250\010\210\140\021\217\218\064" ; 0, 17, 48, 624, 242, "00:17:48.624242", "\041\123\075\057\127\178\144\064" ; 14, 1, 40, 672, 236, "14:01:40.672236", "\102\018\245\130\149\168\232\064" ; 17, 23, 59, 45, 695, "17:23:59.045695", "\083\092\085\118\225\149\238\064" ; 12, 35, 24, 530, 799, "12:35:24.530799", "\056\047\078\252\144\033\230\064" ; 2, 25, 47, 403, 355, "02:25:47.403355", "\215\250\034\161\179\021\193\064" ; 8, 47, 43, 44, 704, "08:47:43.044704", "\128\042\110\220\194\235\222\064" ; 17, 48, 48, 362, 989, "17:48:48.362989", "\122\027\155\157\011\080\239\064" ; 2, 41, 43, 88, 393, "02:41:43.088393", "\025\058\118\080\139\243\194\064" ; 18, 8, 33, 459, 326, "18:08:33.459326", "\135\112\204\178\046\228\239\064" ; 1, 21, 14, 600, 125, "01:21:14.600125", "\131\192\202\161\153\010\179\064" ; 20, 47, 11, 923, 118, "20:47:11.923118", "\069\097\023\197\254\068\242\064" ; 21, 58, 19, 231, 218, "21:58:19.231218", "\068\165\017\179\179\079\243\064" ; 18, 46, 18, 33, 477, "18:46:18.033477", "\194\045\031\137\160\127\240\064" ; 14, 40, 3, 418, 329, "14:40:03.418329", "\191\127\243\098\109\200\233\064" ; 12, 28, 48, 82, 382, "12:28:48.082382", "\121\147\223\162\002\240\229\064" ; 5, 41, 4, 533, 516, "05:41:04.533516", "\249\074\032\037\034\252\211\064" ; 3, 30, 20, 10, 534, "03:30:20.010534", "\192\152\045\089\001\166\200\064" ; 16, 4, 32, 555, 594, "16:04:32.555594", "\123\017\109\199\017\066\236\064" ; 16, 24, 38, 528, 578, "16:24:38.528578", "\236\104\028\234\208\216\236\064" ; 11, 39, 2, 708, 549, "11:39:02.708549", "\211\243\110\172\214\122\228\064" ; 4, 5, 34, 613, 816, "04:05:34.613816", "\225\206\133\145\078\199\204\064" ; 23, 12, 32, 522, 779, "23:12:32.522779", "\064\131\077\093\008\102\244\064" ; 20, 14, 28, 870, 965, "20:14:28.870965", "\239\254\120\239\077\202\241\064" ; 0, 11, 54, 773, 644, "00:11:54.773644", "\249\245\067\108\048\086\134\064" ; 16, 7, 57, 492, 439, "16:07:57.492439", "\009\111\015\194\175\091\236\064" ; 5, 8, 36, 951, 619, "05:08:36.951619", "\208\096\083\231\060\021\210\064" ; 23, 10, 59, 204, 647, "23:10:59.204647", "\195\238\059\070\051\096\244\064" ; 22, 53, 16, 526, 749, "22:53:16.526749", "\003\092\144\109\200\029\244\064" ; 1, 32, 5, 157, 192, "01:32:05.157192", "\050\035\188\061\040\149\181\064" ; 11, 48, 28, 187, 57, "11:48:28.187057", "\047\246\094\252\133\193\228\064" ; 5, 44, 51, 338, 903, "05:44:51.338903", "\097\053\150\176\213\052\212\064" ; 19, 10, 57, 280, 869, "19:10:57.280869", "\023\126\112\126\020\220\240\064" ; 23, 18, 22, 121, 565, "23:18:22.121565", "\053\036\238\241\225\123\244\064" ; 8, 53, 42, 934, 478, "08:53:42.934478", "\054\208\124\206\187\069\223\064" ; 5, 35, 4, 34, 477, "05:35:04.034477", "\222\004\223\052\002\162\211\064" ; 7, 30, 8, 862, 665, "07:30:08.862665", "\154\066\231\053\055\096\218\064" ; 11, 18, 41, 158, 506, "11:18:41.158506", "\199\044\123\018\037\226\227\064" ; 20, 27, 31, 998, 695, "20:27:31.998695", "\187\155\167\250\063\251\241\064" ; 0, 6, 23, 598, 660, "00:06:23.598660", "\198\022\130\028\148\249\119\064" ; 2, 36, 44, 974, 454, "02:36:44.974454", "\187\158\232\186\124\094\194\064" ; 2, 19, 40, 915, 30, "02:19:40.915030", "\110\250\179\031\117\094\192\064" ; 21, 1, 3, 290, 841, "21:01:03.290841", "\117\228\072\167\244\120\242\064" ; 22, 43, 37, 289, 73, "22:43:37.289073", "\147\002\011\160\148\249\243\064" ; 4, 43, 8, 54, 294, "04:43:08.054294", "\152\138\141\121\003\151\208\064" ; 1, 31, 10, 880, 623, "01:31:10.880623", "\027\073\130\112\225\094\181\064" ; 4, 37, 34, 930, 20, "04:37:34.930020", "\040\155\114\133\187\067\208\064" ; 9, 12, 19, 10, 505, "09:12:19.010505", "\239\148\014\086\096\046\224\064" ; 18, 14, 12, 657, 415, "18:14:12.657415", "\079\151\197\132\074\007\240\064" ; 16, 7, 47, 813, 41, "16:07:47.813041", "\042\143\110\004\122\090\236\064" ; 4, 18, 5, 292, 36, "04:18:05.292036", "\160\134\111\097\165\062\206\064" ; 12, 1, 56, 489, 726, "12:01:56.489726", "\064\220\213\171\143\038\229\064" ; 13, 55, 59, 858, 6, "13:55:59.858006", "\185\255\200\116\251\125\232\064" ; 3, 3, 7, 504, 73, "03:03:07.504073", "\230\204\118\133\192\117\197\064" ; 8, 37, 14, 892, 283, "08:37:14.892283", "\242\039\042\027\185\078\222\064" ; 21, 57, 13, 168, 955, "21:57:13.168955", "\120\040\010\180\146\075\243\064" ; 14, 33, 58, 448, 893, "14:33:58.448893", "\076\218\084\093\206\154\233\064" ; 7, 20, 52, 371, 124, "07:20:52.371124", "\176\224\126\192\023\213\217\064" ; 4, 32, 50, 361, 941, "04:32:50.361941", "\011\043\021\084\046\249\207\064" ; 22, 43, 39, 158, 556, "22:43:39.158556", "\041\004\114\137\178\249\243\064" ; 10, 58, 14, 803, 389, "10:58:14.803389", "\031\217\092\181\217\072\227\064" ; 7, 46, 6, 730, 821, "07:46:06.730821", "\143\113\197\197\174\079\219\064" ; 5, 36, 46, 896, 260, "05:36:46.896260", "\046\231\082\092\185\187\211\064" ; 5, 6, 42, 951, 757, "05:06:42.951757", "\048\049\150\233\188\248\209\064" ; 13, 7, 15, 168, 685, "13:07:15.168685", "\202\021\222\101\101\016\231\064" ; 0, 35, 33, 131, 150, "00:35:33.131150", "\189\193\023\038\067\170\160\064" ; 21, 13, 21, 665, 759, "21:13:21.665759", "\192\232\242\166\026\167\242\064" ; 14, 57, 54, 996, 11, "14:57:54.996011", "\238\117\082\223\095\078\234\064" ; 11, 20, 26, 2, 804, "11:20:26.002804", "\010\106\248\022\064\239\227\064" ; 4, 41, 9, 833, 668, "04:41:09.833668", "\238\006\209\090\117\121\208\064" ; 13, 9, 7, 789, 951, "13:09:07.789951", "\206\081\071\071\121\030\231\064" ; 11, 16, 57, 158, 139, "11:16:57.158139", "\040\133\121\015\037\213\227\064" ; 22, 12, 26, 501, 753, "22:12:26.501753", "\091\039\046\007\168\132\243\064" ; 0, 7, 28, 233, 639, "00:07:28.233639", "\031\129\063\252\188\003\124\064" ; 6, 47, 57, 149, 98, "06:47:57.149098", "\122\086\210\138\073\231\215\064" ; 6, 32, 23, 749, 892, "06:32:23.749892", "\226\003\059\254\239\253\214\064" ; 19, 13, 32, 341, 255, "19:13:32.341255", "\138\205\199\117\197\229\240\064" ; 6, 47, 35, 324, 515, "06:47:35.324515", "\004\144\218\196\212\225\215\064" ; 3, 19, 29, 922, 59, "03:19:29.922059", "\254\128\007\006\246\096\199\064" ; 1, 3, 41, 275, 322, "01:03:41.275322", "\189\083\001\247\140\218\173\064" ; 15, 34, 54, 37, 864, "15:34:54.037864", "\054\144\046\054\193\099\235\064" ; 19, 38, 40, 487, 255, "19:38:40.487255", "\029\230\203\203\007\068\241\064" ; 6, 34, 12, 399, 505, "06:34:12.399505", "\102\107\125\145\025\025\215\064" ; 7, 38, 41, 125, 173, "07:38:41.125173", "\086\157\213\002\072\224\218\064" ; 18, 51, 55, 317, 201, "18:51:55.317201", "\020\091\065\019\181\148\240\064" ; 17, 36, 5, 982, 571, "17:36:05.982571", "\224\188\056\113\191\240\238\064" ; 22, 42, 11, 308, 302, "22:42:11.308302", "\245\019\206\238\052\244\243\064" ; 1, 2, 19, 31, 61, "01:02:19.031061", "\093\054\058\231\015\054\173\064" ; 16, 49, 5, 341, 592, "16:49:05.341592", "\146\088\082\238\042\144\237\064" ; 20, 59, 43, 639, 197, "20:59:43.639197", "\043\162\038\058\250\115\242\064" ; 16, 15, 13, 724, 118, "16:15:13.724118", "\015\131\249\043\055\146\236\064" ; 21, 58, 59, 242, 584, "21:58:59.242584", "\168\194\159\225\051\082\243\064" ; 5, 41, 52, 175, 264, "05:41:52.175264", "\010\127\134\055\011\008\212\064" ; 14, 35, 18, 244, 572, "14:35:18.244572", "\176\168\136\211\199\164\233\064" ; 4, 52, 12, 123, 499, "04:52:12.123499", "\134\089\104\231\007\031\209\064" ; 9, 1, 46, 899, 97, "09:01:46.899097", "\188\036\206\138\185\190\223\064" ; 2, 55, 16, 281, 24, "02:55:16.281024", "\179\044\152\248\035\138\196\064" ; 18, 58, 22, 670, 200, "18:58:22.670200", "\156\162\035\185\234\172\240\064" ; 19, 27, 21, 768, 786, "19:27:21.768786", "\122\140\242\076\156\025\241\064" ; 5, 17, 43, 202, 899, "05:17:43.202899", "\089\022\076\252\204\157\210\064" ; 4, 36, 16, 59, 558, "04:36:16.059558", "\142\091\204\207\003\048\208\064" ; 21, 15, 46, 927, 53, "21:15:46.927053", "\202\134\053\213\046\176\242\064" ; 19, 9, 38, 796, 19, "19:09:38.796019", "\064\107\126\188\044\215\240\064" ; 10, 58, 13, 594, 917, "10:58:13.594917", "\090\096\143\009\179\072\227\064" ; 13, 19, 48, 908, 215, "13:19:48.908215", "\088\231\024\016\157\110\231\064" ; 8, 45, 5, 869, 426, "08:45:05.869426", "\018\243\172\164\119\196\222\064" ; 18, 19, 57, 608, 775, "18:19:57.608775", "\185\218\138\189\217\028\240\064" ; 20, 27, 11, 396, 946, "20:27:11.396946", "\132\012\228\089\246\249\241\064" ; 1, 16, 47, 481, 37, "01:16:47.481037", "\042\167\061\037\123\255\177\064" ; 3, 27, 53, 397, 733, "03:27:53.397733", "\198\057\234\232\178\092\200\064" ; 23, 9, 29, 103, 708, "23:09:29.103708", "\070\184\201\168\145\090\244\064" ; 1, 31, 37, 934, 903, "01:31:37.934903", "\239\145\205\085\239\121\181\064" ; 13, 46, 31, 459, 0, "13:46:31.459000", "\156\196\032\176\238\054\232\064" ; 20, 22, 41, 99, 439, "20:22:41.099439", "\079\089\077\151\017\233\241\064" ; 13, 6, 27, 297, 652, "13:06:27.297652", "\179\124\093\134\105\010\231\064" ; 7, 44, 31, 762, 155, "07:44:31.762155", "\223\195\037\199\240\055\219\064" ; 8, 25, 3, 933, 368, "08:25:03.933368", "\201\034\077\188\251\151\221\064" ; 12, 50, 27, 679, 501, "12:50:27.679501", "\147\225\120\190\117\146\230\064" ; 17, 17, 7, 131, 168, "17:17:07.131168", "\201\059\135\050\100\098\238\064" ; 14, 35, 53, 677, 471, "14:35:53.677471", "\160\169\215\173\053\169\233\064" ; 12, 21, 15, 744, 699, "12:21:15.744699", "\075\255\146\212\119\183\229\064" ; 10, 51, 38, 86, 470, "10:51:38.086470", "\195\187\092\196\066\023\227\064" ; 21, 11, 18, 511, 83, "21:11:18.511083", "\041\094\101\045\104\159\242\064" ; 17, 27, 33, 322, 441, "17:27:33.322441", "\188\201\111\081\170\176\238\064" ; 18, 59, 19, 532, 21, "18:59:19.532021", "\189\115\040\131\120\176\240\064" ; 14, 58, 17, 629, 826, "14:58:17.629826", "\006\219\136\039\052\081\234\064" ; 14, 47, 29, 659, 663, "14:47:29.659663", "\108\148\245\027\053\000\234\064" ; 10, 51, 38, 66, 737, "10:51:38.066737", "\014\162\181\034\066\023\227\064" ; 4, 24, 17, 711, 993, "04:24:17.711993", "\253\044\150\034\219\248\206\064" ; 0, 19, 53, 722, 752, "00:19:53.722752", "\121\172\025\025\228\166\146\064" ; 5, 19, 8, 715, 799, "05:19:08.715799", "\225\155\166\207\045\179\210\064" ; 19, 10, 5, 684, 968, "19:10:05.684968", "\108\001\161\245\218\216\240\064" ; 19, 17, 37, 446, 508, "19:17:37.446508", "\150\146\229\036\023\245\240\064" ; 12, 25, 20, 593, 447, "12:25:20.593447", "\029\144\132\253\018\214\229\064" ; 1, 40, 21, 801, 774, "01:40:21.801774", "\201\148\015\065\205\133\183\064" ; 9, 40, 40, 869, 51, "09:40:40.869051", "\242\010\068\207\027\003\225\064" ; 3, 35, 28, 656, 167, "03:35:28.656167", "\220\190\071\253\083\064\201\064" ; 0, 36, 55, 874, 92, "00:36:55.874092", "\100\147\252\136\191\079\161\064" ; 11, 0, 52, 147, 118, "11:00:52.147118", "\213\206\048\181\132\092\227\064" ; 21, 14, 26, 527, 589, "21:14:26.527589", "\204\041\001\113\040\171\242\064" ; 14, 20, 11, 110, 78, "14:20:11.110078", "\064\076\194\133\099\051\233\064" ; 23, 40, 48, 962, 201, "23:40:48.962201", "\051\224\044\101\015\208\244\064" ; 6, 21, 37, 516, 545, "06:21:37.516545", "\122\194\018\015\097\092\214\064" ; 12, 36, 14, 857, 402, "12:36:14.857402", "\177\081\214\111\219\039\230\064" ; 8, 39, 8, 791, 628, "08:39:08.791628", "\167\124\008\170\050\107\222\064" ; 2, 33, 6, 847, 922, "02:33:06.847922", "\199\069\181\136\108\241\193\064" ; 23, 47, 38, 143, 716, "23:47:38.143716", "\254\037\169\076\162\233\244\064" ; 11, 0, 42, 216, 521, "11:00:42.216521", "\189\114\189\237\070\091\227\064" ; 14, 42, 33, 40, 542, "14:42:33.040542", "\132\188\030\076\033\219\233\064" ; 1, 35, 25, 825, 682, "01:35:25.825682", "\229\066\229\095\211\093\182\064" ; 18, 8, 19, 286, 729, "18:08:19.286729", "\186\075\226\044\105\226\239\064" ; 21, 12, 51, 38, 631, "21:12:51.038631", "\026\138\059\158\048\165\242\064" ; 1, 50, 12, 616, 995, "01:50:12.616995", "\204\098\098\243\157\212\185\064" ; 9, 37, 19, 884, 419, "09:37:19.884419", "\031\019\041\077\252\233\224\064" ; 15, 33, 3, 614, 356, "15:33:03.614356", "\003\234\205\168\243\085\235\064" ; 8, 40, 44, 144, 353, "08:40:44.144353", "\133\093\020\061\009\131\222\064" ; 10, 49, 57, 23, 135, "10:49:57.023135", "\141\156\133\189\160\010\227\064" ; 2, 55, 33, 837, 392, "02:55:33.837392", "\247\058\169\047\235\146\196\064" ; 7, 48, 1, 384, 690, "07:48:01.384690", "\070\206\194\158\088\108\219\064" ; 22, 11, 50, 357, 21, "22:11:50.357021", "\240\166\091\182\101\130\243\064" ; 21, 41, 32, 986, 825, "21:41:32.986825", "\222\002\009\202\207\016\243\064" ; 5, 11, 41, 538, 950, "05:11:41.538950", "\012\036\040\126\098\067\210\064" ; 11, 24, 13, 973, 116, "11:24:13.973116", "\103\042\196\035\191\011\228\064" ; 16, 58, 1, 872, 517, "16:58:01.872517", "\135\197\168\235\059\211\237\064" ; 8, 30, 12, 93, 970, "08:30:12.093970", "\052\191\154\003\006\229\221\064" ; 9, 55, 41, 152, 443, "09:55:41.152443", "\112\036\208\224\164\115\225\064" ; 13, 20, 58, 405, 954, "13:20:58.405954", "\054\062\147\253\076\119\231\064" ; 14, 56, 12, 422, 851, "14:56:12.422851", "\002\210\254\135\141\065\234\064" ; 13, 8, 15, 492, 486, "13:08:15.492486", "\247\255\113\194\239\023\231\064" ; 14, 6, 16, 177, 450, "14:06:16.177450", "\086\159\171\173\005\203\232\064" ; 23, 5, 0, 854, 897, "23:05:00.854897", "\008\122\168\173\205\073\244\064" ; 16, 28, 3, 665, 514, "16:28:03.665514", "\033\004\228\075\117\242\236\064" ; 12, 7, 27, 286, 116, "12:07:27.286116", "\220\189\220\039\233\079\229\064" ; 1, 7, 56, 336, 462, "01:07:56.336462", "\177\076\191\068\172\216\175\064" ; 5, 0, 35, 22, 431, "05:00:35.022431", "\219\110\130\111\193\156\209\064" ; 23, 44, 16, 370, 717, "23:44:16.370717", "\241\242\116\238\005\221\244\064" ; 0, 32, 0, 29, 930, "00:32:00.029930", "\173\076\248\165\030\000\158\064" ; 1, 40, 5, 475, 289, "01:40:05.475289", "\038\055\138\172\121\117\183\064" ; 18, 26, 45, 220, 910, "18:26:45.220910", "\150\236\216\136\083\054\240\064" ; 6, 0, 18, 773, 657, "06:00:18.773657", "\085\166\152\131\177\028\213\064" ; 14, 15, 22, 467, 560, "14:15:22.467560", "\157\099\064\246\078\015\233\064" ; 2, 41, 3, 356, 763, "02:41:03.356763", "\182\244\104\170\173\223\194\064" ; 19, 58, 56, 399, 545, "19:58:56.399545", "\069\076\137\100\006\144\241\064" ; 10, 11, 0, 975, 394, "10:11:00.975394", "\087\122\109\054\159\230\225\064" ; 9, 37, 34, 171, 332, "09:37:34.171332", "\025\063\141\123\197\235\224\064" ; 0, 48, 22, 220, 561, "00:48:22.220561", "\139\019\095\237\112\172\166\064" ; 3, 10, 33, 485, 881, "03:10:33.485881", "\096\062\089\049\190\084\198\064" ; 6, 54, 28, 261, 388, "06:54:28.261388", "\228\187\148\186\016\073\216\064" ; 20, 46, 39, 239, 977, "20:46:39.239977", "\109\031\242\214\243\066\242\064" ; 4, 17, 41, 570, 462, "04:17:41.570462", "\206\024\230\004\201\050\206\064" ; 17, 21, 8, 202, 478, "17:21:08.202478", "\133\036\179\122\134\128\238\064" ; 6, 53, 24, 194, 659, "06:53:24.194659", "\184\005\075\117\012\057\216\064" ; 4, 59, 57, 780, 153, "04:59:57.780153", "\056\217\006\238\113\147\209\064" ; 13, 29, 12, 881, 232, "13:29:12.881232", "\134\115\013\051\028\181\231\064" ; 5, 17, 29, 554, 493, "05:17:29.554493", "\055\053\208\124\099\154\210\064" ; 7, 7, 46, 342, 488, "07:07:46.342488", "\210\201\082\235\149\016\217\064" ; 2, 27, 16, 555, 967, "02:27:16.555967", "\084\057\237\041\071\066\193\064" ; 8, 17, 26, 398, 491, "08:17:26.398491", "\048\101\224\128\153\037\221\064" ; 15, 35, 26, 34, 936, "15:35:26.034936", "\046\026\050\030\193\103\235\064" ; 5, 41, 36, 909, 865, "05:41:36.909865", "\178\104\058\059\058\004\212\064" ; 6, 8, 30, 964, 985, "06:08:30.964985", "\008\114\080\194\189\151\213\064" ; 3, 14, 47, 366, 186, "03:14:47.366186", "\032\207\046\223\174\211\198\064" ; 15, 9, 47, 876, 20, "15:09:47.876020", "\084\024\091\008\124\167\234\064" ; 14, 35, 30, 458, 235, "14:35:30.458235", "\092\114\220\169\078\166\233\064" ; 13, 38, 15, 970, 48, "13:38:15.970048", "\114\026\162\010\255\248\231\064" ; 1, 41, 52, 23, 189, "01:41:52.023189", "\161\220\182\239\005\224\183\064" ; 22, 24, 11, 924, 188, "22:24:11.924188", "\054\091\121\201\190\176\243\064" ; 1, 54, 8, 324, 245, "01:54:08.324245", "\228\102\184\001\083\192\186\064" ; 14, 34, 19, 477, 270, "14:34:19.477270", "\043\188\203\069\111\157\233\064" ; 12, 32, 40, 650, 496, "12:32:40.650496", "\198\252\220\208\020\013\230\064" ; 16, 8, 18, 367, 901, "16:08:18.367901", "\101\081\216\197\075\094\236\064" ; 10, 45, 38, 365, 532, "10:45:38.365532", "\052\042\112\178\075\234\226\064" ; 5, 52, 17, 21, 301, "05:52:17.021301", "\152\222\254\092\065\164\212\064" ; 21, 32, 24, 550, 396, "21:32:24.550396", "\062\009\108\206\136\238\242\064" ; 10, 51, 48, 278, 458, "10:51:48.278458", "\106\192\032\233\136\024\227\064" ; 16, 0, 53, 89, 191, "16:00:53.089191", "\131\021\167\218\162\038\236\064" ; 10, 3, 12, 430, 986, "10:03:12.430986", "\225\038\163\202\013\172\225\064" ; 22, 32, 37, 37, 574, "22:32:37.037574", "\211\049\231\153\080\208\243\064" ; 13, 46, 13, 584, 493, "13:46:13.584493", "\248\169\042\180\178\052\232\064" ; 21, 18, 59, 280, 100, "21:18:59.280100", "\058\035\074\123\052\188\242\064" ; 20, 56, 45, 626, 49, "20:56:45.626049", "\203\244\075\004\218\104\242\064" ; 7, 20, 42, 288, 882, "07:20:42.288882", "\154\237\010\125\146\210\217\064" ; 19, 32, 45, 784, 243, "19:32:45.784243", "\082\099\066\140\220\045\241\064" ; 1, 41, 34, 340, 785, "01:41:34.340785", "\248\141\175\061\087\206\183\064" ; 6, 5, 9, 482, 949, "06:05:09.482949", "\041\236\162\232\094\101\213\064" ; 10, 34, 20, 419, 190, "10:34:20.419190", "\154\037\001\106\141\149\226\064" ; 7, 34, 39, 934, 486, "07:34:39.934486", "\037\094\158\206\251\163\218\064" ; 21, 18, 3, 893, 802, "21:18:03.893802", "\113\083\003\077\190\184\242\064" ; 3, 2, 32, 424, 42, "03:02:32.424042", "\017\029\002\071\054\100\197\064" ; 12, 39, 22, 479, 559, "12:39:22.479559", "\176\029\140\088\079\063\230\064" ; 6, 6, 22, 256, 96, "06:06:22.256096", "\041\122\224\099\144\119\213\064" ; 17, 30, 29, 412, 781, "17:30:29.412781", "\237\127\128\053\173\198\238\064" ; 10, 40, 40, 256, 374, "10:40:40.256374", "\050\063\055\052\008\197\226\064" ; 2, 33, 12, 198, 512, "02:33:12.198512", "\239\089\215\104\025\244\193\064" ; 21, 49, 19, 848, 659, "21:49:19.848659", "\167\117\027\148\253\045\243\064" ; 19, 38, 34, 580, 806, "19:38:34.580806", "\117\059\251\074\169\067\241\064" ; 20, 50, 52, 183, 178, "20:50:52.183178", "\246\013\076\238\194\082\242\064" ; 10, 26, 17, 538, 678, "10:26:17.538678", "\034\165\217\060\049\089\226\064" ; 18, 21, 48, 573, 830, "18:21:48.573830", "\184\093\104\046\201\035\240\064" ; 8, 0, 29, 819, 672, "08:00:29.819672", "\092\140\129\117\116\039\220\064" ; 12, 27, 40, 576, 515, "12:27:40.576515", "\213\149\207\114\146\231\229\064" ; 13, 15, 18, 594, 798, "13:15:18.594798", "\183\208\149\008\211\076\231\064" ; 0, 56, 15, 325, 851, "00:56:15.325851", "\188\056\241\213\166\094\170\064" ; 20, 37, 44, 536, 134, "20:37:44.536134", "\196\062\001\148\136\033\242\064" ; 7, 40, 42, 118, 488, "07:40:42.118488", "\062\177\078\149\135\254\218\064" ; 12, 43, 25, 854, 702, "12:43:25.854702", "\058\002\184\089\187\093\230\064" ; 9, 56, 5, 921, 606, "09:56:05.921606", "\186\221\203\125\189\118\225\064" ; 22, 45, 25, 742, 813, "22:45:25.742813", "\097\226\143\226\091\000\244\064" ; 9, 59, 0, 904, 43, "09:59:00.904043", "\230\149\235\237\156\140\225\064" ; 19, 17, 36, 749, 337, "19:17:36.749337", "\075\203\072\253\011\245\240\064" ; 3, 16, 20, 884, 313, "03:16:20.884313", "\055\027\043\049\113\002\199\064" ; 4, 20, 15, 312, 68, "04:20:15.312068", "\016\031\216\241\167\127\206\064" ; 15, 40, 11, 65, 668, "15:40:11.065668", "\013\199\243\025\098\139\235\064" ; 5, 26, 53, 375, 882, "05:26:53.375882", "\074\096\115\014\088\039\211\064" ; 10, 41, 31, 168, 749, "10:41:31.168749", "\135\077\100\102\101\203\226\064" ; 16, 20, 14, 869, 14, "16:20:14.869014", "\184\114\246\206\219\183\236\064" ; 21, 14, 2, 673, 207, "21:14:02.673207", "\007\180\116\197\170\169\242\064" ; 10, 57, 49, 638, 423, "10:57:49.638423", "\064\018\246\109\180\069\227\064" ; 4, 8, 21, 979, 409, "04:08:21.979409", "\052\044\070\093\253\026\205\064" ; 15, 5, 41, 842, 59, "15:05:41.842059", "\073\183\037\242\186\136\234\064" ; 6, 48, 20, 284, 484, "06:48:20.284484", "\015\097\252\052\018\237\215\064" ; 5, 26, 56, 694, 1, "05:26:56.694001", "\153\043\131\106\044\040\211\064" ; 17, 39, 28, 482, 85, "17:39:28.482085", "\157\133\061\109\015\010\239\064" ; 9, 16, 47, 830, 245, "09:16:47.830245", "\086\246\093\145\250\079\224\064" ; 2, 25, 49, 344, 966, "02:25:49.344966", "\029\140\216\039\172\022\193\064" ; 8, 6, 40, 606, 201, "08:06:40.606201", "\115\071\255\203\038\132\220\064" ; 11, 35, 14, 450, 207, "11:35:14.450207", "\173\130\024\104\078\094\228\064" ; 22, 56, 41, 23, 25, "22:56:41.023025", "\096\118\079\094\144\042\244\064" ; 18, 26, 8, 383, 302, "18:26:08.383302", "\040\071\001\034\006\052\240\064" ; 13, 26, 52, 214, 28, "13:26:52.214028", "\142\063\081\217\134\163\231\064" ; 17, 1, 48, 217, 254, "17:01:48.217254", "\029\169\190\243\134\239\237\064" ; 6, 26, 38, 593, 455, "06:26:38.593455", "\042\174\042\251\165\167\214\064" ; 13, 34, 0, 82, 231, "13:34:00.082231", "\247\231\162\161\002\217\231\064" ; 9, 15, 6, 95, 731, "09:15:06.095731", "\071\117\058\016\067\067\224\064" ; 18, 51, 49, 108, 227, "18:51:49.108227", "\024\060\076\187\081\148\240\064" ; 22, 29, 21, 722, 991, "22:29:21.722991", "\196\002\095\145\027\196\243\064" ; 11, 57, 5, 222, 27, "11:57:05.222027", "\251\093\216\026\039\002\229\064" ; 5, 24, 25, 682, 424, "05:24:25.682424", "\129\182\213\172\107\002\211\064" ; 6, 56, 13, 73, 455, "06:56:13.073455", "\175\153\124\179\068\099\216\064" ; 14, 34, 35, 345, 7, "14:34:35.345007", "\189\030\076\010\107\159\233\064" ; 13, 20, 49, 471, 71, "13:20:49.471071", "\099\125\003\019\047\118\231\064" ; 16, 31, 30, 184, 874, "16:31:30.184874", "\252\224\124\234\069\012\237\064" ; 21, 48, 31, 243, 354, "21:48:31.243354", "\246\041\199\228\243\042\243\064" ; 19, 38, 42, 350, 613, "19:38:42.350613", "\137\096\028\156\037\068\241\064" ; 10, 41, 21, 381, 983, "10:41:21.381983", "\148\105\052\057\044\202\226\064" ; 16, 5, 31, 868, 877, "16:05:31.868877", "\104\035\215\205\123\073\236\064" ; 23, 56, 57, 57, 362, "23:56:57.057362", "\161\106\244\234\144\012\245\064" ; 10, 20, 10, 612, 914, "10:20:10.612914", "\040\210\253\156\083\043\226\064" ; 15, 22, 54, 198, 548, "15:22:54.198548", "\214\085\129\090\198\009\235\064" ; 8, 22, 50, 396, 939, "08:22:50.396939", "\225\213\114\103\153\118\221\064" ; 6, 2, 19, 76, 980, "06:02:19.076980", "\157\133\061\237\196\058\213\064" ; 15, 29, 58, 943, 768, "15:29:58.943768", "\224\242\088\051\222\062\235\064" ; 20, 4, 49, 346, 162, "20:04:49.346162", "\082\042\225\137\021\166\241\064" ; 12, 25, 3, 699, 946, "12:25:03.699946", "\095\039\245\101\246\211\229\064" ; 18, 19, 11, 206, 587, "18:19:11.206587", "\141\043\046\078\243\025\240\064" ; 3, 16, 44, 113, 803, "03:16:44.113803", "\152\193\024\145\014\014\199\064" ; 9, 30, 7, 507, 492, "09:30:07.507492", "\223\220\095\061\240\179\224\064" ; 12, 58, 7, 483, 875, "12:58:07.483875", "\139\108\231\123\239\203\230\064" ; 14, 13, 24, 468, 353, "14:13:24.468353", "\064\110\191\252\142\000\233\064" ; 23, 45, 16, 509, 57, "23:45:16.509057", "\237\243\024\037\200\224\244\064" ; 4, 27, 48, 450, 494, "04:27:48.450494", "\134\146\201\169\057\098\207\064" ; 14, 59, 53, 527, 646, "14:59:53.527646", "\060\221\121\226\048\093\234\064" ; 9, 0, 47, 873, 4, "09:00:47.873004", "\082\043\076\223\247\175\223\064" ; 2, 33, 41, 379, 208, "02:33:41.379208", "\049\067\227\137\176\002\194\064" ; 3, 17, 42, 161, 432, "03:17:42.161432", "\068\196\205\169\020\043\199\064" ; 18, 41, 57, 56, 835, "18:41:57.056835", "\036\209\203\232\080\111\240\064" ; 17, 44, 33, 430, 705, "17:44:33.430705", "\039\218\085\200\045\048\239\064" ; 22, 15, 42, 352, 638, "22:15:42.352638", "\085\190\103\164\229\144\243\064" ; 17, 7, 38, 608, 277, "17:07:38.608277", "\189\083\001\119\083\027\238\064" ; 8, 21, 7, 610, 982, "08:21:07.610982", "\029\063\084\026\231\092\221\064" ; 6, 23, 20, 573, 924, "06:23:20.573924", "\153\186\043\187\036\118\214\064" ; 17, 22, 35, 585, 766, "17:22:35.585766", "\163\086\152\190\114\139\238\064" ; 5, 11, 26, 433, 423, "05:11:26.433423", "\150\210\051\189\155\063\210\064" ; 20, 45, 17, 964, 120, "20:45:17.964120", "\215\023\009\109\223\061\242\064" ; 9, 9, 29, 64, 688, "09:09:29.064688", "\142\145\236\017\034\025\224\064" ; 21, 15, 24, 759, 172, "21:15:24.759172", "\001\138\145\037\204\174\242\064" ; 16, 35, 46, 173, 860, "16:35:46.173860", "\195\216\066\144\069\044\237\064" ; 7, 11, 21, 364, 82, "07:11:21.364082", "\196\150\030\077\087\070\217\064" ; 16, 45, 11, 282, 793, "16:45:11.282793", "\209\231\163\012\233\114\237\064" ; 11, 20, 14, 343, 643, "11:20:14.343643", "\208\154\031\255\202\237\227\064" ; 21, 9, 7, 315, 511, "21:09:07.315511", "\041\067\085\012\053\151\242\064" ; 0, 15, 21, 902, 339, "00:15:21.902339", "\063\119\130\253\055\207\140\064" ; 0, 1, 9, 69, 460, "00:01:09.069460", "\085\024\091\008\114\068\081\064" ; 8, 7, 30, 547, 104, "08:07:30.547104", "\224\126\192\003\163\144\220\064" ; 3, 48, 49, 418, 249, "03:48:49.418249", "\075\232\046\137\181\208\202\064" ; 3, 24, 27, 767, 472, "03:24:27.767472", "\076\194\133\060\226\245\199\064" ; 0, 0, 15, 146, 358, "00:00:15.146358", "\021\004\143\111\239\074\046\064" ; 20, 51, 48, 920, 993, "20:51:48.920993", "\237\039\099\188\078\086\242\064" ; 22, 55, 42, 685, 968, "22:55:42.685968", "\225\148\185\249\234\038\244\064" ; 9, 7, 52, 450, 326, "09:07:52.450326", "\081\018\018\105\014\013\224\064" ; 1, 12, 53, 891, 211, "01:12:53.891211", "\213\114\103\038\228\021\177\064" ; 21, 32, 36, 953, 540, "21:32:36.953540", "\182\040\179\065\079\239\242\064" ; 23, 3, 0, 299, 830, "23:03:00.299830", "\198\138\026\204\068\066\244\064" ; 14, 47, 38, 65, 798, "14:47:38.065798", "\069\104\004\027\066\001\234\064" ; 5, 54, 55, 482, 103, "05:54:55.482103", "\147\138\198\218\222\203\212\064" ; 19, 22, 4, 97, 996, "19:22:04.097996", "\242\064\100\145\193\005\241\064" ; 23, 5, 33, 749, 749, "23:05:33.749749", "\179\206\248\254\219\075\244\064" ; 20, 53, 30, 216, 413, "20:53:30.216413", "\087\122\109\118\163\092\242\064" ; 6, 47, 4, 402, 305, "06:47:04.402305", "\129\120\093\191\025\218\215\064" ; 20, 25, 34, 122, 6, "20:25:34.122006", "\063\144\188\243\225\243\241\064" ; 14, 54, 16, 536, 112, "14:54:16.536112", "\096\090\212\039\017\051\234\064" ; 10, 9, 18, 187, 436, "10:09:18.187436", "\067\200\121\255\197\217\225\064" ; 23, 49, 27, 446, 428, "23:49:27.446428", "\192\175\145\036\119\240\244\064" ; 3, 21, 0, 803, 250, "03:21:00.803250", "\065\096\229\208\102\142\199\064" ; 17, 9, 53, 777, 333, "17:09:53.777333", "\164\116\233\223\056\044\238\064" ; 11, 42, 49, 169, 515, "11:42:49.169515", "\166\184\170\108\037\151\228\064" ; 15, 28, 54, 987, 566, "15:28:54.987566", "\021\003\036\154\223\054\235\064" ; 6, 2, 45, 575, 557, "06:02:45.575557", "\255\006\237\213\100\065\213\064" ; 14, 44, 23, 774, 998, "14:44:23.774998", "\015\155\200\204\248\232\233\064" ; 12, 3, 54, 680, 622, "12:03:54.680622", "\222\201\167\199\085\053\229\064" ; 10, 3, 20, 182, 575, "10:03:20.182575", "\194\134\167\215\005\173\225\064" ; 16, 29, 3, 886, 785, "16:29:03.886785", "\178\239\138\096\252\249\236\064" ; 13, 16, 2, 216, 259, "13:16:02.216259", "\143\254\151\235\070\082\231\064" ; 3, 16, 33, 855, 11, "03:16:33.855011", "\092\029\000\113\237\008\199\064" ; 3, 44, 24, 443, 4, "03:44:24.443004", "\255\229\090\180\056\076\202\064" ; 23, 30, 12, 407, 481, "23:30:12.407481", "\012\204\010\133\070\168\244\064" ; 23, 0, 52, 296, 661, "23:00:52.296661", "\208\154\031\191\068\058\244\064" ; 23, 33, 31, 205, 609, "23:33:31.205609", "\172\169\044\074\179\180\244\064" ; 15, 0, 23, 11, 543, "15:00:23.011543", "\240\108\143\094\224\096\234\064" ; 20, 25, 23, 997, 435, "20:25:23.997435", "\014\103\126\245\063\243\241\064" ; 0, 18, 35, 322, 609, "00:18:35.322609", "\148\129\003\090\074\109\145\064" ; 23, 52, 54, 134, 436, "23:52:54.134436", "\247\092\166\038\098\253\244\064" ; 5, 48, 39, 656, 933, "05:48:39.656933", "\170\181\048\011\234\109\212\064" ; 4, 3, 10, 542, 65, "04:03:10.542065", "\167\203\098\098\069\127\204\064" ; 0, 11, 2, 865, 46, "00:11:02.865046", "\073\188\060\157\235\182\132\064" ; 9, 21, 44, 728, 602, "09:21:44.728602", "\058\036\181\080\023\117\224\064" ; 14, 21, 58, 559, 879, "14:21:58.559879", "\087\093\135\234\209\064\233\064" ; 11, 7, 1, 977, 995, "11:07:01.977995", "\149\043\188\075\191\138\227\064" ; 10, 51, 31, 566, 643, "10:51:31.566643", "\048\128\240\033\114\022\227\064" ; 11, 58, 15, 922, 809, "11:58:15.922809", "\110\189\166\135\253\010\229\064" ; 1, 7, 17, 471, 794, "01:07:17.471794", "\230\176\251\142\241\138\175\064" ; 23, 52, 51, 749, 908, "23:52:51.749908", "\240\135\159\255\059\253\244\064" ; 18, 51, 12, 110, 242, "18:51:12.110242", "\138\029\141\195\001\146\240\064" ; 1, 55, 28, 798, 494, "01:55:28.798494", "\013\080\026\106\204\016\187\064" ; 9, 9, 49, 451, 790, "09:09:49.451790", "\085\077\016\117\174\027\224\064" ; 6, 2, 45, 501, 67, "06:02:45.501067", "\135\082\123\017\096\065\213\064" ; 1, 28, 59, 18, 324, "01:28:59.018324", "\187\180\225\176\004\219\180\064" ; 9, 11, 5, 43, 117, "09:11:05.043117", "\029\231\054\097\033\037\224\064" ; 7, 35, 14, 718, 320, "07:35:14.718320", "\004\115\244\248\173\172\218\064" ; 16, 30, 30, 129, 941, "16:30:30.129941", "\045\007\122\040\196\004\237\064" ; 19, 16, 50, 545, 672, "19:16:50.545672", "\037\144\018\187\040\242\240\064" ; 14, 35, 3, 361, 152, "14:35:03.361152", "\156\163\142\142\235\162\233\064" ; 7, 16, 1, 875, 892, "07:16:01.875892", "\181\081\157\014\120\140\217\064" ; 23, 0, 56, 244, 908, "23:00:56.244908", "\169\166\036\235\131\058\244\064" ; 19, 47, 45, 375, 793, "19:47:45.375793", "\081\133\063\003\022\102\241\064" ; 9, 51, 56, 861, 815, "09:51:56.861815", "\006\013\253\147\155\087\225\064" ; 13, 36, 20, 727, 954, "13:36:20.727954", "\224\047\102\075\151\234\231\064" ; 17, 49, 44, 114, 193, "17:49:44.114193", "\014\020\120\167\003\087\239\064" ; 20, 12, 27, 230, 515, "20:12:27.230515", "\036\127\048\176\179\194\241\064" ; 19, 1, 34, 277, 219, "19:01:34.277219", "\173\048\125\111\228\184\240\064" ; 3, 42, 31, 555, 231, "03:42:31.555231", "\093\053\207\017\199\019\202\064" ; 20, 47, 26, 528, 678, "20:47:26.528678", "\002\016\119\117\232\069\242\064" ; 18, 11, 45, 471, 361, "18:11:45.471361", "\243\169\099\021\047\252\239\064" ; 9, 39, 42, 762, 851, "09:39:42.762851", "\023\128\070\105\216\251\224\064" ; 3, 43, 30, 312, 838, "03:43:30.312838", "\121\089\019\011\040\049\202\064" ; 8, 0, 42, 53, 639, "08:00:42.053639", "\179\069\210\110\131\042\220\064" ; 16, 50, 12, 745, 978, "16:50:12.745978", "\049\065\013\223\151\152\237\064" ; 17, 4, 5, 736, 844, "17:04:05.736844", "\072\222\057\148\183\000\238\064" ; 9, 15, 31, 55, 676, "09:15:31.055676", "\230\008\025\200\097\070\224\064" ; 23, 41, 59, 956, 874, "23:41:59.956874", "\135\028\091\079\127\212\244\064" ; 16, 15, 17, 615, 521, "16:15:17.615521", "\160\024\089\178\179\146\236\064" ; 19, 42, 51, 69, 3, "19:42:51.069003", "\197\227\162\026\177\083\241\064" ; 18, 27, 57, 733, 976, "18:27:57.733976", "\064\158\093\190\219\058\240\064" ; 16, 42, 35, 140, 354, "16:42:35.140354", "\252\171\199\125\100\095\237\064" ; 1, 39, 4, 210, 58, "01:39:04.210058", "\067\112\092\198\053\056\183\064" ; 7, 11, 16, 778, 670, "07:11:16.778670", "\024\178\186\213\049\069\217\064" ; 18, 18, 54, 173, 182, "18:18:54.173182", "\036\125\090\197\226\024\240\064" ; 0, 46, 46, 520, 407, "00:46:46.520407", "\056\075\201\114\010\237\165\064" ; 0, 7, 39, 222, 433, "00:07:39.222433", "\209\200\231\021\143\179\124\064" ; 1, 44, 46, 86, 593, "01:44:46.086593", "\016\119\245\042\022\142\184\064" ; 15, 19, 27, 536, 591, "15:19:27.536591", "\139\227\192\043\241\239\234\064" ; 3, 1, 16, 595, 501, "03:01:16.595501", "\222\115\096\057\076\062\197\064" ; 19, 53, 13, 110, 366, "19:53:13.110366", "\137\035\015\196\145\122\241\064" ; 19, 12, 41, 185, 930, "19:12:41.185930", "\085\188\145\249\146\226\240\064" ; 5, 59, 36, 751, 44, "05:59:36.751044", "\119\218\026\017\048\018\213\064" ; 2, 4, 49, 364, 18, "02:04:49.364018", "\039\157\072\048\093\065\189\064" ; 4, 32, 18, 150, 499, "04:32:18.150499", "\138\029\141\067\019\233\207\064" ; 3, 46, 5, 426, 974, "03:46:05.426974", "\031\131\021\167\182\126\202\064" ; 18, 57, 24, 416, 320, "18:57:24.416320", "\011\041\063\169\070\169\240\064" ; 4, 58, 45, 601, 26, "04:58:45.601026", "\131\193\053\119\102\129\209\064" ; 23, 54, 40, 26, 341, "23:54:40.026341", "\089\138\228\107\000\004\245\064" ; 14, 5, 58, 931, 84, "14:05:58.931084", "\058\172\112\203\221\200\232\064" ; 0, 55, 58, 147, 952, "00:55:58.147952", "\193\082\093\192\075\060\170\064" ; 2, 34, 43, 957, 57, "02:34:43.957057", "\180\001\216\128\250\033\194\064" ; 5, 43, 6, 188, 410, "05:43:06.188410", "\015\209\232\014\140\026\212\064" ; 12, 51, 51, 863, 540, "12:51:51.863540", "\089\163\030\162\251\156\230\064" ; 22, 34, 18, 154, 143, "22:34:18.154143", "\126\166\094\119\162\214\243\064" ; 2, 8, 30, 381, 112, "02:08:30.381112", "\029\088\142\144\097\030\190\064" ; 12, 52, 45, 184, 27, "12:52:45.184027", "\083\151\140\227\165\163\230\064" ; 22, 2, 32, 324, 169, "22:02:32.324169", "\086\213\203\047\133\095\243\064" ; 14, 57, 6, 626, 472, "14:57:06.626472", "\251\001\015\012\084\072\234\064" ; 10, 43, 32, 535, 498, "10:43:32.535498", "\163\179\204\034\145\218\226\064" ; 2, 17, 12, 802, 750, "02:17:12.802750", "\110\018\131\192\102\020\192\064" ; 3, 56, 36, 763, 405, "03:56:36.763405", "\078\074\065\183\097\186\203\064" ; 20, 35, 54, 878, 503, "20:35:54.878503", "\103\041\089\014\174\026\242\064" ; 18, 53, 46, 4, 79, "18:53:46.004079", "\058\036\181\016\160\155\240\064" ; 4, 19, 34, 623, 866, "04:19:34.623866", "\139\081\215\218\079\107\206\064" ; 23, 37, 46, 917, 603, "23:37:46.917603", "\187\123\128\174\174\196\244\064" ; 17, 22, 5, 167, 696, "17:22:05.167696", "\118\000\196\093\165\135\238\064" ; 1, 48, 6, 533, 871, "01:48:06.533871", "\073\021\197\171\136\086\185\064" ; 5, 18, 41, 735, 584, "05:18:41.735584", "\222\233\206\019\111\172\210\064" ; 7, 24, 49, 420, 467, "07:24:49.420467", "\131\107\238\232\090\016\218\064" ; 13, 21, 40, 597, 41, "13:21:40.597041", "\044\186\245\026\147\124\231\064" ; 0, 6, 52, 473, 110, "00:06:52.473110", "\146\150\202\219\145\199\121\064" ; 15, 29, 54, 825, 590, "15:29:54.825590", "\061\184\059\107\090\062\235\064" ; 20, 35, 34, 888, 609, "20:35:34.888609", "\031\018\190\055\110\025\242\064" ; 18, 53, 53, 0, 234, "18:53:53.000234", "\230\093\245\000\016\156\240\064" ; 2, 2, 4, 304, 429, "02:02:04.304429", "\244\022\015\239\077\156\188\064" ; 5, 8, 52, 954, 854, "05:08:52.954854", "\158\243\083\028\061\025\210\064" ; 4, 47, 19, 897, 761, "04:47:19.897761", "\168\141\234\116\249\213\208\064" ; 3, 33, 37, 468, 762, "03:33:37.468762", "\206\169\100\000\188\008\201\064" ; 5, 39, 46, 933, 56, "05:39:46.933056", "\086\131\048\183\187\232\211\064" ; 16, 42, 52, 202, 841, "16:42:52.202841", "\169\104\172\125\134\097\237\064" ; 22, 32, 53, 306, 914, "22:32:53.306914", "\139\167\030\233\084\209\243\064" ; 19, 56, 58, 830, 394, "19:56:58.830394", "\013\056\075\073\173\136\241\064" ; 18, 1, 12, 562, 550, "18:01:12.562550", "\139\219\104\000\018\173\239\064" ; 10, 2, 54, 190, 111, "10:02:54.190111", "\244\169\099\021\198\169\225\064" ; 1, 54, 53, 20, 472, "01:54:53.020472", "\124\042\167\061\005\237\186\064" ; 17, 20, 46, 57, 120, "17:20:46.057120", "\126\082\237\211\193\125\238\064" ; 13, 25, 19, 990, 54, "13:25:19.990054", "\232\185\133\174\255\151\231\064" ; 2, 13, 21, 71, 524, "02:13:21.071524", "\225\152\101\079\018\065\191\064" ; 9, 15, 42, 670, 135, "09:15:42.670135", "\157\244\190\113\213\071\224\064" ; 10, 52, 5, 858, 171, "10:52:05.858171", "\108\007\035\118\187\026\227\064" ; 10, 9, 42, 86, 499, "10:09:42.086499", "\005\141\153\196\194\220\225\064" ; 22, 50, 42, 914, 182, "22:50:42.914182", "\010\078\125\160\046\020\244\064" ; 11, 47, 59, 359, 655, "11:47:59.359655", "\219\051\075\130\235\189\228\064" ; 22, 56, 25, 414, 457, "22:56:25.414457", "\202\169\157\161\150\041\244\064" ; 10, 30, 59, 870, 983, "10:30:59.870983", "\140\189\023\223\123\124\226\064" ; 18, 54, 6, 537, 888, "18:54:06.537888", "\142\114\048\155\232\156\240\064" ; 9, 58, 13, 934, 828, "09:58:13.934828", "\236\104\028\234\189\134\225\064" ; 10, 43, 42, 296, 960, "10:43:42.296960", "\007\066\178\128\201\219\226\064" ; 13, 57, 29, 900, 129, "13:57:29.900129", "\038\085\219\205\060\137\232\064" ; 19, 56, 21, 162, 943, "19:56:21.162943", "\130\030\106\155\082\134\241\064" ; 21, 1, 27, 374, 800, "21:01:27.374800", "\232\072\046\255\117\122\242\064" ; 0, 33, 33, 714, 556, "00:33:33.714556", "\164\108\145\180\219\118\159\064" ; 18, 25, 53, 513, 715, "18:25:53.513715", "\072\056\045\056\024\051\240\064" ; 6, 0, 43, 899, 683, "06:00:43.899683", "\113\001\104\148\249\034\213\064" ; 16, 41, 15, 27, 598, "16:41:15.027598", "\110\051\021\226\096\085\237\064" ; 13, 50, 20, 659, 418, "13:50:20.659418", "\013\199\243\025\149\083\232\064" ; 11, 20, 17, 668, 228, "11:20:17.668228", "\200\175\031\098\053\238\227\064" ; 18, 27, 45, 444, 629, "18:27:45.444629", "\094\076\051\029\023\058\240\064" ; 18, 11, 4, 924, 593, "18:11:04.924593", "\035\015\068\150\029\247\239\064" ; 10, 17, 46, 937, 677, "10:17:46.937677", "\039\050\115\001\094\025\226\064" ; 8, 36, 45, 42, 455, "08:36:45.042455", "\036\045\149\183\066\071\222\064" ; 17, 4, 39, 940, 976, "17:04:39.940976", "\075\179\121\028\254\004\238\064" ; 21, 42, 57, 71, 153, "21:42:57.071153", "\000\084\113\035\017\022\243\064" ; 22, 9, 17, 808, 33, "22:09:17.808033", "\210\002\180\237\220\120\243\064" ; 12, 14, 8, 7, 559, "12:14:08.007559", "\057\095\236\061\000\130\229\064" ; 9, 53, 34, 29, 885, "09:53:34.029885", "\053\099\209\244\192\099\225\064" ; 11, 10, 18, 617, 288, "11:10:18.617288", "\135\195\210\192\083\163\227\064" ; 11, 23, 18, 635, 418, "11:23:18.635418", "\042\033\088\085\212\004\228\064" ; 8, 40, 39, 82, 361, "08:40:39.082361", "\093\018\103\069\197\129\222\064" ; 7, 27, 28, 860, 232, "07:27:28.860232", "\190\132\010\014\055\056\218\064" ; 12, 11, 14, 933, 479, "12:11:14.933479", "\016\090\015\223\093\108\229\064" ; 3, 5, 28, 833, 594, "03:05:28.833594", "\018\076\053\179\106\188\197\064" ; 16, 37, 54, 804, 232, "16:37:54.804232", "\076\191\068\188\089\060\237\064" ; 22, 24, 29, 841, 61, "22:24:29.841061", "\015\097\252\116\221\177\243\064" ; 0, 16, 2, 597, 241, "00:16:02.597241", "\164\022\074\038\199\020\142\064" ; 6, 30, 2, 43, 857, "06:30:02.043857", "\045\151\141\206\130\218\214\064" ; 17, 11, 48, 933, 643, "17:11:48.933643", "\228\072\103\224\157\058\238\064" ; 12, 58, 24, 586, 269, "12:58:24.586269", "\181\052\183\194\018\206\230\064" ; 20, 30, 1, 954, 557, "20:30:01.954557", "\147\143\221\069\159\004\242\064" ; 8, 27, 23, 719, 889, "08:27:23.719889", "\240\079\169\018\238\186\221\064" ; 3, 12, 26, 852, 59, "03:12:26.852059", "\162\241\068\016\109\141\198\064" ; 9, 25, 22, 846, 650, "09:25:22.846650", "\165\189\193\023\091\144\224\064" ; 23, 3, 28, 900, 100, "23:03:28.900100", "\242\065\207\102\014\068\244\064" ; 13, 41, 57, 960, 210, "13:41:57.960210", "\105\082\010\186\190\020\232\064" ; 2, 28, 43, 110, 40, "02:28:43.110040", "\161\108\202\021\142\109\193\064" ; 16, 10, 33, 27, 162, "16:10:33.027162", "\182\215\130\222\032\111\236\064" ; 20, 10, 11, 96, 180, "20:10:11.096180", "\041\010\244\137\049\186\241\064" ; 9, 13, 17, 92, 458, "09:13:17.092458", "\200\122\106\245\162\053\224\064" ; 10, 17, 41, 214, 484, "10:17:41.214484", "\176\140\013\221\166\024\226\064" ; 16, 31, 40, 931, 396, "16:31:40.931396", "\244\251\254\205\157\013\237\064" ; 8, 11, 52, 946, 521, "08:11:52.946521", "\255\208\204\147\060\210\220\064" ; 13, 26, 1, 343, 240, "13:26:01.343240", "\214\115\210\251\042\157\231\064" ; 6, 31, 5, 856, 346, "06:31:05.856346", "\004\116\095\206\118\234\214\064" ; 10, 21, 20, 969, 694, "10:21:20.969694", "\036\182\187\007\031\052\226\064" ; 20, 40, 11, 775, 297, "20:40:11.775297", "\187\211\157\103\188\042\242\064" ; 2, 2, 10, 813, 610, "02:02:10.813610", "\179\181\190\072\208\162\188\064" ; 13, 42, 23, 911, 125, "13:42:23.911125", "\178\157\239\039\253\023\232\064" ; 7, 32, 18, 187, 512, "07:32:18.187512", "\231\084\050\000\140\128\218\064" ; 0, 54, 17, 274, 455, "00:54:17.274455", "\114\162\093\133\140\114\169\064" ; 18, 36, 59, 920, 880, "18:36:59.920880", "\185\170\236\187\190\092\240\064" ; 22, 42, 50, 704, 285, "22:42:50.704285", "\033\089\192\068\171\246\243\064" ; 13, 24, 7, 356, 786, "13:24:07.356786", "\053\121\202\106\235\142\231\064" ; 11, 42, 31, 728, 695, "11:42:31.728695", "\057\045\120\081\247\148\228\064" ; 19, 43, 42, 458, 173, "19:43:42.458173", "\046\054\173\084\231\086\241\064" ; 16, 43, 38, 928, 746, "16:43:38.928746", "\009\136\073\184\093\103\237\064" ; 11, 24, 7, 169, 493, "11:24:07.169493", "\125\149\124\108\229\010\228\064" ; 22, 11, 34, 148, 873, "22:11:34.148873", "\164\167\200\097\098\129\243\064" ; 4, 34, 51, 769, 515, "04:34:51.769515", "\178\215\187\063\241\026\208\064" ; 11, 50, 11, 108, 718, "11:50:11.108718", "\208\043\158\122\099\206\228\064" ; 1, 14, 17, 20, 997, "01:14:17.020997", "\081\052\015\096\005\105\177\064" ; 16, 31, 59, 52, 147, "16:31:59.052147", "\115\047\048\171\225\015\237\064" ; 8, 49, 20, 757, 283, "08:49:20.757283", "\181\029\083\119\048\004\223\064" ; 12, 51, 55, 703, 372, "12:51:55.703372", "\030\255\005\130\118\157\230\064" ; 16, 50, 7, 915, 985, "16:50:07.915985", "\084\198\191\079\253\151\237\064" ; 4, 48, 19, 719, 0, "04:48:19.719000", "\117\147\024\004\238\228\208\064" ; 21, 35, 8, 632, 698, "21:35:08.632698", "\036\240\135\031\202\248\242\064" ; 2, 54, 28, 645, 865, "02:54:28.645865", "\081\078\180\171\082\114\196\064" ; 15, 26, 22, 967, 709, "15:26:22.967709", "\097\221\120\247\222\035\235\064" ; 12, 45, 33, 685, 544, "12:45:33.685544", "\127\248\249\239\181\109\230\064" ; 20, 32, 47, 547, 661, "20:32:47.547661", "\069\046\056\195\248\014\242\064" ; 3, 24, 26, 218, 305, "03:24:26.218305", "\199\017\107\241\027\245\199\064" ; 14, 55, 15, 169, 318, "14:55:15.169318", "\020\149\013\107\101\058\234\064" ; 1, 29, 19, 757, 265, "01:29:19.757265", "\103\121\030\220\193\239\180\064" ; 7, 33, 37, 957, 979, "07:33:37.957979", "\208\038\135\079\125\148\218\064" ; 12, 30, 38, 890, 109, "12:30:38.890109", "\156\222\197\123\220\253\229\064" ; 20, 45, 7, 611, 59, "20:45:07.611059", "\079\205\229\198\057\061\242\064" ; 23, 30, 18, 887, 482, "23:30:18.887482", "\093\083\032\051\174\168\244\064" ; 4, 47, 47, 429, 699, "04:47:47.429699", "\008\060\048\128\219\220\208\064" ; 4, 51, 45, 148, 895, "04:51:45.148895", "\227\228\126\135\073\024\209\064" ; 13, 35, 46, 170, 391, "13:35:46.170391", "\145\211\215\115\069\230\231\064" ; 13, 25, 29, 464, 258, "13:25:29.464258", "\221\151\051\219\046\153\231\064" ; 21, 10, 37, 395, 233, "21:10:37.395233", "\149\214\223\082\214\156\242\064" ; 2, 52, 50, 867, 942, "02:52:50.867942", "\106\052\185\024\111\065\196\064" ; 6, 41, 13, 198, 141, "06:41:13.198141", "\192\150\087\174\076\130\215\064" ; 3, 7, 46, 950, 756, "03:07:46.950756", "\061\099\095\178\121\001\198\064" ; 14, 21, 21, 162, 697, "14:21:21.162697", "\197\086\208\052\037\060\233\064" ; 19, 44, 53, 43, 127, "19:44:53.043127", "\234\239\165\176\080\091\241\064" ; 16, 40, 16, 965, 472, "16:40:16.965472", "\038\137\037\229\030\078\237\064" ; 12, 9, 10, 573, 743, "12:09:10.573743", "\169\071\026\092\210\092\229\064" ; 14, 40, 48, 420, 360, "14:40:48.420360", "\145\208\150\115\013\206\233\064" ; 15, 5, 35, 104, 7, "15:05:35.104007", "\242\124\006\084\227\135\234\064" ; 18, 24, 45, 701, 191, "18:24:45.701191", "\212\013\020\056\219\046\240\064" ; 12, 33, 25, 891, 556, "12:33:25.891556", "\210\114\160\135\188\018\230\064" ; 4, 17, 27, 889, 878, "04:17:27.889878", "\183\181\133\231\241\043\206\064" ; 11, 17, 20, 138, 393, "11:17:20.138393", "\032\040\183\109\004\216\227\064" ; 22, 28, 28, 375, 972, "22:28:28.375972", "\067\055\251\003\198\192\243\064" ; 7, 12, 41, 475, 590, "07:12:41.475590", "\019\010\017\112\094\090\217\064" ; 11, 23, 10, 453, 519, "11:23:10.453519", "\036\071\058\131\206\003\228\064" ; 15, 55, 24, 163, 13, "15:55:24.163013", "\250\009\103\055\133\253\235\064" ; 20, 37, 7, 465, 516, "20:37:07.465516", "\188\231\192\114\055\031\242\064" ; 3, 28, 13, 398, 64, "03:28:13.398064", "\219\218\194\243\178\102\200\064" ; 0, 58, 9, 323, 944, "00:58:09.323944", "\120\235\252\219\165\066\171\064" ; 5, 33, 53, 493, 655, "05:33:53.493655", "\032\036\011\152\095\144\211\064" ; 13, 52, 15, 87, 620, "13:52:15.087620", "\079\117\200\205\226\097\232\064" ; 19, 5, 54, 311, 356, "19:05:54.311356", "\215\109\080\251\036\201\240\064" ; 19, 20, 16, 689, 266, "19:20:16.689266", "\004\201\059\007\011\255\240\064" ; 13, 28, 18, 689, 714, "13:28:18.689714", "\051\024\035\018\086\174\231\064" ; 7, 55, 39, 26, 489, "07:55:39.026489", "\045\235\254\177\193\222\219\064" ; 16, 30, 57, 635, 257, "16:30:57.635257", "\242\124\006\084\052\008\237\064" ; 10, 35, 26, 123, 698, "10:35:26.123698", "\019\130\085\245\195\157\226\064" ; 13, 5, 33, 232, 877, "13:05:33.232877", "\096\119\186\115\167\003\231\064" ; 16, 29, 6, 794, 961, "16:29:06.794961", "\019\013\082\112\089\250\236\064" ; 9, 29, 53, 831, 794, "09:29:53.831794", "\096\115\014\158\058\178\224\064" ; 0, 59, 1, 259, 602, "00:59:01.259602", "\244\167\141\234\132\170\171\064" ; 17, 57, 33, 363, 154, "17:57:33.363154", "\045\035\245\158\171\145\239\064" ; 8, 28, 53, 874, 619, "08:28:53.874619", "\093\248\193\249\119\209\221\064" ; 8, 18, 21, 762, 384, "08:18:21.762384", "\191\066\230\202\112\051\221\064" ; 21, 53, 41, 469, 520, "21:53:41.469520", "\077\103\039\131\087\062\243\064" ; 21, 34, 27, 599, 361, "21:34:27.599361", "\088\143\251\150\057\246\242\064" ; 11, 15, 45, 694, 79, "11:15:45.694079", "\187\041\229\053\054\204\227\064" ; 0, 35, 2, 726, 530, "00:35:02.726530", "\032\123\189\251\115\109\160\064" ; 2, 33, 24, 345, 502, "02:33:24.345502", "\090\215\104\057\044\250\193\064" ; 1, 13, 22, 653, 93, "01:13:22.653093", "\063\084\026\049\167\050\177\064" ; 14, 54, 47, 515, 416, "14:54:47.515416", "\251\177\073\126\240\054\234\064" ; 14, 36, 35, 956, 836, "14:36:35.956836", "\244\135\102\158\126\174\233\064" ; 0, 58, 54, 115, 992, "00:58:54.115992", "\050\173\077\099\059\156\171\064" ; 1, 21, 19, 181, 844, "01:21:19.181844", "\249\016\084\141\046\015\179\064" ; 0, 22, 27, 203, 88, "00:22:27.203088", "\215\248\076\246\207\012\149\064" ; 6, 12, 53, 969, 478, "06:12:53.969478", "\013\116\237\011\126\217\213\064" ; 6, 33, 5, 382, 554, "06:33:05.382554", "\189\197\195\123\088\008\215\064" ; 21, 44, 0, 877, 513, "21:44:00.877513", "\077\018\075\010\014\026\243\064" ; 17, 23, 35, 689, 199, "17:23:35.689199", "\174\015\235\013\246\146\238\064" ; 15, 31, 56, 644, 25, "15:31:56.644025", "\026\081\218\155\148\077\235\064" ; 21, 38, 32, 269, 867, "21:38:32.269867", "\052\015\096\081\132\005\243\064" ; 3, 42, 52, 594, 462, "03:42:52.594462", "\091\176\084\023\076\030\202\064" ; 10, 1, 43, 975, 783, "10:01:43.975783", "\032\069\157\057\255\160\225\064" ; 15, 16, 53, 474, 691, "15:16:53.474691", "\023\046\171\048\175\220\234\064" ; 22, 34, 20, 421, 758, "22:34:20.421758", "\013\081\133\191\198\214\243\064" ; 15, 51, 29, 236, 248, "15:51:29.236248", "\055\247\087\143\039\224\235\064" ; 17, 43, 43, 466, 398, "17:43:43.466398", "\157\127\187\236\238\041\239\064" ; 11, 37, 21, 603, 525, "11:37:21.603525", "\043\169\019\080\051\110\228\064" ; 1, 58, 52, 418, 604, "01:58:52.418604", "\249\185\161\041\107\220\187\064" ; 3, 53, 14, 38, 400, "03:53:14.038400", "\022\140\074\234\004\085\203\064" ; 17, 40, 51, 343, 130, "17:40:51.343130", "\009\196\235\250\106\020\239\064" ; 21, 36, 23, 365, 105, "21:36:23.365105", "\042\087\120\215\117\253\242\064" ; 21, 9, 53, 351, 605, "21:09:53.351605", "\129\144\044\160\021\154\242\064" ; 0, 24, 52, 699, 8, "00:24:52.699008", "\146\206\192\200\203\082\151\064" ; 12, 16, 40, 914, 743, "12:16:40.914743", "\167\028\147\069\029\149\229\064" ; 4, 12, 57, 189, 508, "04:12:57.189508", "\042\083\204\065\152\164\205\064" ; 11, 26, 11, 955, 377, "11:26:11.955377", "\075\201\114\146\126\026\228\064" ; 22, 18, 49, 295, 219, "22:18:49.295219", "\226\142\055\185\148\156\243\064" ; 19, 42, 28, 316, 648, "19:42:28.316648", "\070\126\253\016\069\082\241\064" ; 14, 30, 25, 971, 90, "14:30:25.971090", "\239\085\043\019\063\128\233\064" ; 22, 9, 37, 469, 142, "22:09:37.469142", "\179\010\155\129\023\122\243\064" ; 22, 4, 0, 777, 646, "22:04:00.777646", "\158\238\060\113\012\101\243\064" ; 16, 3, 24, 569, 949, "16:03:24.569949", "\109\175\005\061\146\057\236\064" ; 9, 55, 16, 300, 499, "09:55:16.300499", "\048\020\176\157\137\112\225\064" ; 15, 40, 8, 102, 247, "15:40:08.102247", "\036\128\155\069\003\139\235\064" ; 3, 33, 12, 487, 793, "03:33:12.487793", "\027\067\000\112\062\252\200\064" ; 16, 54, 11, 357, 930, "16:54:11.357930", "\137\157\041\116\107\182\237\064" ; 15, 42, 55, 206, 794, "15:42:55.206794", "\096\115\014\158\230\159\235\064" ; 4, 55, 25, 806, 681, "04:55:25.806681", "\084\088\169\160\115\079\209\064" ; 20, 37, 29, 358, 427, "20:37:29.358427", "\048\243\029\188\149\032\242\064" ; 9, 46, 57, 714, 138, "09:46:57.714138", "\091\239\055\218\054\050\225\064" ; 4, 33, 24, 52, 808, "04:33:24.052808", "\062\206\052\097\003\005\208\064" ; 1, 47, 40, 637, 942, "01:47:40.637942", "\190\186\042\080\163\060\185\064" ; 6, 59, 47, 406, 75, "06:59:47.406075", "\046\255\033\253\217\152\216\064" ; 1, 59, 3, 468, 956, "01:59:03.468956", "\067\027\128\013\120\231\187\064" ; 8, 42, 34, 360, 603, "08:42:34.360603", "\246\154\030\020\151\158\222\064" ; 11, 32, 30, 180, 619, "11:32:30.180619", "\065\127\161\199\197\073\228\064" ; 23, 59, 30, 767, 312, "23:59:30.767312", "\158\242\232\070\044\022\245\064" ; 14, 30, 33, 995, 782, "14:30:33.995782", "\127\054\114\221\063\129\233\064" ; 22, 14, 43, 220, 494, "22:14:43.220494", "\112\183\036\135\051\141\243\064" ; 5, 44, 49, 421, 166, "05:44:49.421166", "\012\061\098\244\090\052\212\064" ; 5, 17, 56, 720, 393, "05:17:56.720393", "\209\061\235\026\046\161\210\064" ; 20, 12, 49, 928, 501, "20:12:49.928501", "\085\221\035\219\030\196\241\064" ; 10, 46, 29, 671, 417, "10:46:29.671417", "\032\129\063\124\181\240\226\064" ; 1, 39, 57, 218, 669, "01:39:57.218669", "\166\011\177\250\055\109\183\064" ; 2, 59, 46, 360, 71, "02:59:46.360071", "\159\120\206\022\046\017\197\064" ; 21, 40, 36, 259, 702, "21:40:36.259702", "\204\072\189\039\068\013\243\064" ; 6, 39, 15, 992, 931, "06:39:15.992931", "\011\119\046\140\255\100\215\064" ; 11, 3, 40, 899, 781, "11:03:40.899781", "\018\134\001\203\156\113\227\064" ; 7, 56, 2, 340, 316, "07:56:02.340316", "\148\194\188\199\149\228\219\064" ; 18, 43, 2, 415, 637, "18:43:02.415637", "\160\251\114\166\102\115\240\064" ; 4, 22, 58, 76, 644, "04:22:58.076644", "\183\120\120\207\009\209\206\064" ; 1, 11, 12, 870, 70, "01:11:12.870070", "\059\083\232\188\222\176\176\064" ; 11, 48, 14, 947, 739, "11:48:14.947739", "\069\189\224\083\222\191\228\064" ; 17, 11, 28, 167, 942, "17:11:28.167942", "\180\230\199\095\005\056\238\064" ; 2, 23, 10, 574, 771, "02:23:10.574771", "\217\155\024\146\073\199\192\064" ; 23, 29, 40, 993, 37, "23:29:40.993037", "\236\195\122\227\079\166\244\064" ; 11, 19, 59, 392, 6, "11:19:59.392006", "\187\042\080\139\236\235\227\064" ; 16, 30, 12, 976, 541, "16:30:12.976541", "\071\233\210\063\159\002\237\064" ; 16, 23, 22, 818, 100, "16:23:22.818100", "\027\013\224\045\090\207\236\064" ; 19, 45, 28, 793, 113, "19:45:28.793113", "\209\065\151\176\140\093\241\064" ; 21, 20, 8, 780, 484, "21:20:08.780484", "\113\202\220\124\140\192\242\064" ; 0, 30, 34, 330, 767, "00:30:34.330767", "\098\158\149\180\082\169\156\064" ; 0, 36, 49, 495, 84, "00:36:49.495084", "\139\105\166\123\253\066\161\064" ; 14, 28, 18, 939, 22, "14:28:18.939022", "\135\221\119\012\094\112\233\064" ; 2, 34, 49, 428, 507, "02:34:49.428507", "\142\063\081\217\182\036\194\064" ; 15, 43, 47, 267, 312, "15:43:47.267312", "\058\229\209\141\104\166\235\064" ; 20, 4, 20, 998, 933, "20:04:20.998933", "\095\043\161\251\079\164\241\064" ; 7, 54, 50, 492, 640, "07:54:50.492640", "\044\236\105\135\159\210\219\064" ; 5, 51, 43, 373, 946, "05:51:43.373946", "\030\052\187\238\215\155\212\064" ; 1, 26, 13, 438, 991, "01:26:13.438991", "\061\212\182\097\112\053\180\064" ; 19, 46, 55, 752, 720, "19:46:55.752720", "\112\032\036\011\252\098\241\064" ; 17, 21, 8, 599, 744, "17:21:08.599744", "\063\084\026\049\147\128\238\064" ; 18, 1, 59, 516, 725, "18:01:59.516725", "\001\222\002\137\240\178\239\064" ; 19, 5, 22, 824, 457, "19:05:22.824457", "\191\210\249\048\045\199\240\064" ; 4, 23, 27, 941, 399, "04:23:27.941399", "\191\046\195\127\248\223\206\064" ; 9, 51, 50, 52, 407, "09:51:50.052407", "\227\113\081\173\193\086\225\064" ; 18, 39, 33, 162, 300, "18:39:33.162300", "\130\226\199\152\082\102\240\064" ; 10, 53, 24, 822, 799, "10:53:24.822799", "\134\145\094\084\154\036\227\064" ; 0, 5, 41, 779, 799, "00:05:41.779799", "\065\039\132\014\122\092\117\064" ; 4, 35, 8, 880, 550, "04:35:08.880550", "\032\099\238\090\056\031\208\064" ; 15, 43, 45, 131, 758, "15:43:45.131758", "\160\141\092\055\036\166\235\064" ; 14, 45, 11, 957, 763, "14:45:11.957763", "\074\151\254\165\254\238\233\064" ; 11, 8, 36, 170, 241, "11:08:36.170241", "\238\064\157\114\133\150\227\064" ; 19, 31, 58, 932, 827, "19:31:58.932827", "\029\001\220\236\238\042\241\064" ; 10, 52, 59, 329, 21, "10:52:59.329021", "\086\012\087\135\106\033\227\064" ; 15, 3, 54, 936, 428, "15:03:54.936428", "\098\218\055\247\093\123\234\064" ; 13, 32, 58, 543, 932, "13:32:58.543932", "\232\020\228\103\081\209\231\064" ; 22, 42, 36, 26, 10, "22:42:36.026010", "\054\118\137\106\192\245\243\064" ; 18, 7, 0, 94, 680, "18:07:00.094680", "\242\089\158\007\131\216\239\064" ; 11, 27, 2, 751, 57, "11:27:02.751057", "\141\176\168\008\216\032\228\064" ; 16, 51, 56, 849, 19, "16:51:56.849019", "\214\228\041\043\155\165\237\064" ; 23, 53, 13, 320, 900, "23:53:13.320900", "\213\009\104\034\149\254\244\064" ; 16, 1, 13, 151, 494, "16:01:13.151494", "\241\241\009\217\036\041\236\064" ; 14, 56, 30, 500, 924, "14:56:30.500924", "\185\196\145\007\208\067\234\064" ; 17, 1, 52, 702, 240, "17:01:52.702240", "\062\005\192\120\022\240\237\064" ; 2, 3, 33, 399, 761, "02:03:33.399761", "\056\165\188\086\102\245\188\064" ; 20, 38, 34, 735, 843, "20:38:34.735843", "\064\079\003\198\171\036\242\064" ; 9, 4, 22, 718, 326, "09:04:22.718326", "\120\157\013\249\173\229\223\064" ; 9, 14, 50, 218, 281, "09:14:50.218281", "\139\111\040\252\070\065\224\064" ; 6, 52, 19, 547, 770, "06:52:19.547770", "\238\230\169\014\227\040\216\064" ; 18, 18, 25, 655, 936, "18:18:25.655936", "\068\191\182\126\026\023\240\064" ; 1, 44, 34, 857, 190, "01:44:34.857190", "\117\200\205\112\219\130\184\064" ; 15, 13, 25, 384, 441, "15:13:25.384441", "\071\054\087\077\172\194\234\064" ; 1, 2, 25, 181, 245, "01:02:25.181245", "\033\007\037\204\092\066\173\064" ; 6, 42, 32, 799, 633, "06:42:32.799633", "\243\227\047\045\051\150\215\064" ; 0, 3, 29, 709, 523, "00:03:29.709523", "\080\024\148\105\180\054\106\064" ; 7, 42, 15, 500, 984, "07:42:15.500984", "\244\049\031\016\224\021\219\064" ; 19, 59, 37, 409, 63, "19:59:37.409063", "\240\164\133\139\150\146\241\064" ; 23, 19, 32, 415, 423, "23:19:32.415423", "\112\150\146\165\070\128\244\064" ; 9, 15, 59, 564, 0, "09:15:59.564000", "\094\186\073\012\242\073\224\064" ; 9, 10, 48, 186, 324, "09:10:48.186324", "\207\191\093\246\005\035\224\064" ; 3, 19, 27, 621, 206, "03:19:27.621206", "\010\159\173\131\207\095\199\064" ; 12, 19, 50, 274, 228, "12:19:50.274228", "\116\204\121\198\200\172\229\064" ; 1, 32, 42, 783, 333, "01:32:42.783333", "\225\240\130\136\200\186\181\064" ; 0, 2, 14, 789, 839, "00:02:14.789839", "\095\067\112\092\070\217\096\064" ; 12, 51, 4, 586, 913, "12:51:04.586913", "\148\197\253\199\018\151\230\064" ; 3, 35, 26, 966, 645, "03:35:26.966645", "\236\250\005\187\123\063\201\064" ; 0, 38, 35, 729, 463, "00:38:35.729463", "\072\161\044\124\117\023\162\064" ; 20, 13, 45, 521, 911, "20:13:45.521911", "\070\089\191\089\152\199\241\064" ; 11, 25, 37, 622, 116, "11:25:37.622116", "\075\208\095\232\051\022\228\064" ; 9, 58, 3, 309, 84, "09:58:03.309084", "\247\032\004\228\105\133\225\064" ; 6, 11, 20, 802, 36, "06:11:20.802036", "\142\205\142\084\051\194\213\064" ; 23, 26, 29, 399, 316, "23:26:29.399316", "\141\044\153\099\086\154\244\064" ; 20, 27, 17, 837, 845, "20:27:17.837845", "\162\040\208\103\093\250\241\064" ; 22, 22, 49, 639, 668, "22:22:49.639668", "\068\131\020\060\154\171\243\064" ; 12, 18, 35, 13, 291, "12:18:35.013291", "\074\063\225\108\096\163\229\064" ; 9, 54, 2, 91, 402, "09:54:02.091402", "\025\227\195\236\066\103\225\064" ; 20, 44, 18, 610, 824, "20:44:18.610824", "\250\098\239\197\041\058\242\064" ; 17, 29, 9, 271, 752, "17:29:09.271752", "\020\064\049\178\168\188\238\064" ; 5, 7, 47, 477, 860, "05:07:47.477860", "\004\028\066\149\222\008\210\064" ; 3, 43, 21, 977, 441, "03:43:21.977441", "\099\100\201\028\253\044\202\064" ; 18, 44, 48, 482, 903, "18:44:48.482903", "\002\127\248\185\007\122\240\064" ; 5, 39, 2, 590, 46, "05:39:02.590046", "\073\076\080\195\165\221\211\064" ; 23, 58, 9, 987, 456, "23:58:09.987456", "\163\169\158\204\031\017\245\064" ; 1, 0, 57, 856, 378, "01:00:57.856378", "\008\094\045\119\182\147\172\064" ; 11, 54, 28, 816, 962, "11:54:28.816962", "\002\126\141\036\154\238\228\064" ; 16, 3, 43, 935, 879, "16:03:43.935879", "\064\132\184\242\253\059\236\064" ; 23, 38, 28, 544, 565, "23:38:28.544565", "\024\202\137\182\072\199\244\064" ; 10, 0, 10, 7, 728, "10:00:10.007728", "\104\202\078\063\064\149\225\064" ; 0, 25, 35, 782, 517, "00:25:35.782517", "\065\238\034\076\033\255\151\064" ; 23, 22, 51, 280, 239, "23:22:51.280239", "\193\227\219\123\180\140\244\064" ; 0, 4, 7, 812, 468, "00:04:07.812468", "\126\033\228\188\255\249\110\064" ; 17, 43, 50, 664, 701, "17:43:50.664701", "\019\008\059\069\213\042\239\064" ; 4, 45, 0, 189, 689, "04:45:00.189689", "\218\084\221\035\012\179\208\064" ; 20, 50, 19, 817, 149, "20:50:19.817149", "\111\212\010\019\189\080\242\064" ; 20, 21, 47, 976, 7, "20:21:47.976007", "\026\132\185\157\191\229\241\064" ; 7, 16, 7, 965, 354, "07:16:07.965354", "\196\036\092\200\253\141\217\064" ; 10, 2, 42, 518, 997, "10:02:42.518997", "\183\152\159\155\080\168\225\064" ; 1, 27, 59, 246, 538, "01:27:59.246538", "\057\071\029\029\063\159\180\064" ; 4, 36, 24, 287, 646, "04:36:24.287646", "\181\196\202\104\018\050\208\064" ; 7, 55, 5, 747, 617, "07:55:05.747617", "\060\249\244\216\111\214\219\064" ; 21, 55, 49, 106, 433, "21:55:49.106433", "\227\022\243\179\081\070\243\064" ; 0, 53, 2, 187, 650, "00:53:02.187650", "\048\042\169\019\096\220\168\064" ; 16, 6, 13, 177, 94, "16:06:13.177094", "\075\009\193\170\165\078\236\064" ; 23, 20, 3, 654, 464, "23:20:03.654464", "\070\062\175\120\058\130\244\064" ; 16, 8, 42, 268, 7, "16:08:42.268007", "\131\106\131\147\072\097\236\064" ; 17, 33, 0, 686, 410, "17:33:00.686410", "\181\026\018\247\149\217\238\064" ; 1, 13, 39, 94, 791, "01:13:39.094791", "\245\020\057\068\024\067\177\064" ; 19, 4, 38, 88, 638, "19:04:38.088638", "\243\173\015\107\097\196\240\064" ; 10, 45, 36, 98, 970, "10:45:36.098970", "\041\034\195\042\003\234\226\064" ; 14, 49, 39, 758, 199, "14:49:39.758199", "\156\140\042\067\120\016\234\064" ; 18, 39, 43, 496, 389, "18:39:43.496389", "\145\151\053\241\247\102\240\064" ; 14, 10, 52, 544, 376, "14:10:52.544376", "\152\055\135\107\145\237\232\064" ; 16, 19, 42, 270, 43, "16:19:42.270043", "\176\055\049\164\200\179\236\064" ; 0, 50, 8, 490, 67, "00:50:08.490067", "\178\211\015\234\250\128\167\064" ; 15, 36, 30, 223, 487, "15:36:30.223487", "\130\053\206\038\199\111\235\064" ; 0, 36, 25, 446, 130, "00:36:25.446130", "\135\191\038\107\228\018\161\064" ; 5, 30, 34, 471, 708, "05:30:34.471708", "\081\192\118\048\158\094\211\064" ; 5, 34, 17, 129, 199, "05:34:17.129199", "\235\225\203\068\072\150\211\064" ; 19, 22, 36, 793, 704, "19:22:36.793704", "\044\247\002\179\204\007\241\064" ; 13, 2, 8, 24, 799, "13:02:08.024799", "\191\069\039\203\000\234\230\064" ; 16, 7, 30, 833, 95, "16:07:30.833095", "\111\216\182\168\090\088\236\064" ; 16, 1, 8, 960, 496, "16:01:08.960496", "\126\027\098\188\158\040\236\064" ; 13, 6, 53, 276, 534, "13:06:53.276534", "\199\212\093\217\168\013\231\064" ; 16, 27, 21, 271, 240, "16:27:21.271240", "\044\130\255\173\040\237\236\064" ; 11, 13, 42, 490, 53, "11:13:42.490053", "\010\161\131\174\207\188\227\064" ; 16, 6, 27, 956, 939, "16:06:27.956939", "\168\137\062\159\126\080\236\064" ; 13, 13, 15, 355, 887, "13:13:15.355887", "\067\034\109\099\107\061\231\064" ; 11, 28, 12, 475, 52, "11:28:12.475052", "\125\064\160\051\143\041\228\064" ; 4, 52, 28, 64, 499, "04:52:28.064499", "\232\105\192\032\004\035\209\064" ; 16, 11, 41, 981, 471, "16:11:41.981471", "\223\222\053\104\191\119\236\064" ; 18, 30, 12, 493, 652, "18:30:12.493652", "\186\163\255\229\071\067\240\064" ; 22, 28, 20, 372, 409, "22:28:20.372409", "\188\035\099\245\069\192\243\064" ; 4, 30, 42, 286, 131, "04:30:42.286131", "\176\203\240\159\036\185\207\064" ; 21, 15, 52, 466, 236, "21:15:52.466236", "\068\225\179\117\135\176\242\064" ; 7, 16, 2, 35, 256, "07:16:02.035256", "\191\097\162\065\130\140\217\064" ; 3, 2, 54, 436, 398, "03:02:54.436398", "\005\193\227\219\055\111\197\064" ; 22, 19, 23, 630, 599, "22:19:23.630599", "\031\250\238\022\186\158\243\064" ; 22, 29, 28, 677, 766, "22:29:28.677766", "\069\041\033\216\138\196\243\064" ; 10, 33, 10, 324, 829, "10:33:10.324829", "\121\201\255\100\202\140\226\064" ; 14, 30, 58, 441, 816, "14:30:58.441816", "\219\078\091\035\078\132\233\064" ; 11, 19, 55, 135, 56, "11:19:55.135056", "\228\245\096\082\100\235\227\064" ; 1, 57, 10, 147, 210, "01:57:10.147210", "\165\247\141\175\037\118\187\064" ; 1, 9, 41, 42, 927, "01:09:41.042927", "\030\141\067\253\010\085\176\064" ; 15, 50, 7, 23, 607, "15:50:07.023607", "\159\119\099\193\224\213\235\064" ; 21, 39, 45, 361, 367, "21:39:45.361367", "\110\195\040\200\021\010\243\064" ; 11, 59, 26, 877, 239, "11:59:26.877239", "\249\133\087\018\220\019\229\064" ; 13, 26, 48, 934, 415, "13:26:48.934415", "\061\073\186\230\029\163\231\064" ; 21, 19, 42, 479, 557, "21:19:42.479557", "\250\245\067\172\231\190\242\064" ; 10, 4, 45, 63, 294, "10:04:45.063294", "\129\035\129\006\162\183\225\064" ; 6, 36, 12, 178, 570, "06:36:12.178570", "\131\221\176\109\011\055\215\064" ; 16, 45, 43, 376, 286, "16:45:43.376286", "\254\239\136\010\236\118\237\064" ; 13, 55, 25, 665, 377, "13:55:25.665377", "\208\180\196\074\181\121\232\064" ; 8, 38, 4, 205, 95, "08:38:04.205095", "\101\199\070\032\013\091\222\064" ; 4, 57, 55, 642, 46, "04:57:55.642046", "\034\027\072\023\233\116\209\064" ; 13, 24, 55, 474, 624, "13:24:55.474624", "\189\171\030\048\239\148\231\064" ; 11, 55, 25, 970, 469, "11:55:25.970469", "\025\001\021\014\191\245\228\064" ; 4, 8, 19, 305, 423, "04:08:19.305423", "\057\210\025\024\167\025\205\064" ; 17, 10, 13, 738, 25, "17:10:13.738025", "\212\154\230\157\183\046\238\064" ; 10, 17, 48, 358, 834, "10:17:48.358834", "\214\112\145\123\139\025\226\064" ; 19, 49, 9, 763, 932, "19:49:09.763932", "\198\194\016\057\092\107\241\064" ; 0, 20, 8, 358, 919, "00:20:08.358919", "\167\091\118\136\111\225\146\064" ; 23, 52, 2, 858, 769, "23:52:02.858769", "\029\144\132\189\045\250\244\064" ; 23, 56, 14, 534, 278, "23:56:14.534278", "\144\022\103\140\232\009\245\064" ; 16, 29, 12, 309, 168, "16:29:12.309168", "\031\074\180\228\009\251\236\064" ; 8, 50, 31, 515, 382, "08:50:31.515382", "\188\200\004\252\224\021\223\064" ; 17, 23, 15, 604, 866, "17:23:15.604866", "\015\241\015\091\115\144\238\064" ; 3, 50, 36, 293, 435, "03:50:36.293435", "\064\048\071\143\037\006\203\064" ; 19, 15, 48, 957, 544, "19:15:48.957544", "\071\168\025\082\079\238\240\064" ; 0, 15, 45, 437, 622, "00:15:45.437622", "\021\144\246\063\128\139\141\064" ; 13, 7, 7, 847, 507, "13:07:07.847507", "\004\000\199\030\123\015\231\064" ; 19, 6, 6, 483, 802, "19:06:06.483802", "\123\042\167\189\231\201\240\064" ; 18, 56, 57, 158, 873, "18:56:57.158873", "\051\106\190\138\146\167\240\064" ; 4, 32, 59, 602, 443, "04:32:59.602443", "\091\043\218\028\205\253\207\064" ; 5, 5, 56, 590, 323, "05:05:56.590323", "\197\030\218\199\037\237\209\064" ; 1, 51, 10, 693, 960, "01:51:10.693960", "\188\208\092\167\177\014\186\064" ; 4, 57, 9, 3, 130, "04:57:09.003130", "\233\043\072\051\064\105\209\064" ; 5, 35, 23, 365, 696, "05:35:23.365696", "\018\050\144\103\215\166\211\064" ; 17, 11, 25, 517, 513, "17:11:25.517513", "\072\108\119\143\176\055\238\064" ; 17, 55, 22, 740, 767, "17:55:22.740767", "\222\254\092\180\087\129\239\064" ; 12, 59, 48, 120, 289, "12:59:48.120289", "\035\081\104\217\131\216\230\064" ; 19, 47, 35, 296, 109, "19:47:35.296109", "\113\202\220\188\116\101\241\064" ; 0, 35, 25, 34, 64, "00:35:25.034064", "\241\043\214\112\017\154\160\064" ; 8, 5, 3, 153, 632, "08:05:03.153632", "\231\079\027\213\201\107\220\064" ; 8, 24, 24, 421, 281, "08:24:24.421281", "\091\149\068\246\026\142\221\064" ; 22, 18, 7, 211, 310, "22:18:07.211310", "\053\152\134\097\243\153\243\064" ; 23, 42, 29, 541, 998, "23:42:29.541998", "\072\024\006\172\088\214\244\064" ; 7, 27, 38, 161, 769, "07:27:38.161769", "\032\093\108\090\138\058\218\064" ; 12, 11, 14, 142, 696, "12:11:14.142696", "\169\051\247\144\068\108\229\064" ; 11, 23, 36, 252, 542, "11:23:36.252542", "\220\245\210\020\008\007\228\064" ; 20, 48, 41, 555, 216, "20:48:41.555216", "\035\044\042\226\152\074\242\064" ; 17, 23, 36, 603, 166, "17:23:36.603166", "\130\200\034\077\019\147\238\064" ; 10, 58, 54, 398, 695, "10:58:54.398695", "\067\004\028\194\204\077\227\064" ; 10, 33, 11, 509, 528, "10:33:11.509528", "\012\170\013\078\240\140\226\064" ; 18, 44, 17, 295, 732, "18:44:17.295732", "\070\122\081\187\020\120\240\064" ; 15, 15, 49, 254, 269, "15:15:49.254269", "\236\189\248\034\168\212\234\064" ; 12, 49, 51, 185, 379, "12:49:51.185379", "\203\240\159\238\229\141\230\064" ; 23, 50, 35, 896, 319, "23:50:35.896319", "\124\151\082\087\190\244\244\064" ; 3, 51, 24, 680, 499, "03:51:24.680499", "\251\090\151\026\087\030\203\064" ; 9, 32, 57, 62, 554, "09:32:57.062554", "\007\063\113\000\034\201\224\064" ; 6, 32, 39, 895, 411, "06:32:39.895411", "\095\240\105\078\249\001\215\064" ; 3, 50, 7, 349, 994, "03:50:07.349994", "\230\119\154\204\172\247\202\064" ; 12, 55, 2, 901, 459, "12:55:02.901459", "\118\139\192\216\220\180\230\064" ; 7, 13, 57, 501, 58, "07:13:57.501058", "\218\146\085\017\096\109\217\064" ; 18, 1, 40, 955, 965, "18:01:40.955965", "\100\233\067\151\158\176\239\064" ; 1, 6, 0, 440, 384, "01:06:00.440384", "\093\251\002\122\225\240\174\064" ; 14, 9, 59, 634, 112, "14:09:59.634112", "\192\063\165\074\244\230\232\064" ; 21, 0, 41, 519, 494, "21:00:41.519494", "\200\240\216\079\152\119\242\064" ; 19, 38, 56, 900, 611, "19:38:56.900611", "\118\020\231\104\014\069\241\064" ; 11, 29, 51, 858, 446, "11:29:51.858446", "\236\190\099\120\251\053\228\064" ; 14, 44, 25, 344, 675, "14:44:25.344675", "\152\221\147\007\043\233\233\064" ; 8, 58, 27, 548, 514, "08:58:27.548514", "\217\118\218\026\227\140\223\064" ; 19, 22, 28, 739, 420, "19:22:28.739420", "\224\016\170\212\075\007\241\064" ; 2, 56, 48, 478, 351, "02:56:48.478351", "\129\006\155\058\061\184\196\064" ; 7, 24, 53, 858, 981, "07:24:53.858981", "\185\113\139\249\118\017\218\064" ; 6, 44, 37, 418, 966, "06:44:37.418966", "\009\197\086\208\090\181\215\064" ; 6, 46, 23, 573, 526, "06:46:23.573526", "\090\101\166\180\228\207\215\064" ; 15, 18, 53, 725, 208, "15:18:53.725208", "\089\104\231\052\183\235\234\064" ; 18, 13, 32, 507, 790, "18:13:32.507790", "\052\104\232\031\200\004\240\064" ; 0, 36, 7, 910, 690, "00:36:07.910690", "\150\173\245\069\210\239\160\064" ; 3, 48, 11, 242, 883, "03:48:11.242883", "\225\070\202\022\159\189\202\064" ; 5, 24, 12, 952, 583, "05:24:12.952583", "\239\175\030\247\060\255\210\064" ; 7, 14, 31, 129, 955, "07:14:31.129955", "\189\198\046\081\200\117\217\064" ; 22, 26, 55, 80, 91, "22:26:55.080091", "\027\128\013\072\241\186\243\064" ; 10, 27, 4, 115, 295, "10:27:04.115295", "\204\035\127\176\003\095\226\064" ; 0, 50, 43, 745, 585, "00:50:43.745585", "\198\046\081\189\125\199\167\064" ; 3, 17, 10, 29, 455, "03:17:10.029455", "\218\114\046\197\003\027\199\064" ; 6, 59, 13, 282, 939, "06:59:13.282939", "\241\045\172\027\082\144\216\064" ; 12, 59, 18, 697, 961, "12:59:18.697961", "\156\078\178\085\214\212\230\064" ; 2, 56, 51, 858, 826, "02:56:51.858826", "\122\167\002\238\237\185\196\064" ; 15, 42, 56, 96, 420, "15:42:56.096420", "\085\101\223\021\003\160\235\064" ; 16, 21, 49, 983, 85, "16:21:49.983085", "\134\172\110\117\191\195\236\064" ; 6, 16, 3, 394, 359, "06:16:03.394359", "\249\135\045\061\217\008\214\064" ; 5, 12, 41, 250, 388, "05:12:41.250388", "\212\099\091\006\080\082\210\064" ; 10, 38, 49, 785, 724, "10:38:49.785724", "\118\168\166\036\057\183\226\064" ; 5, 15, 16, 993, 221, "05:15:16.993221", "\044\208\238\144\063\121\210\064" ; 22, 2, 36, 730, 375, "22:02:36.730375", "\045\178\157\175\203\095\243\064" ; 20, 35, 22, 117, 61, "20:35:22.117061", "\234\090\123\223\161\024\242\064" ; 3, 47, 47, 622, 446, "03:47:47.622446", "\195\126\079\172\207\177\202\064" ; 5, 13, 31, 808, 281, "05:13:31.808281", "\063\059\224\186\243\094\210\064" ; 13, 22, 21, 108, 581, "13:22:21.108581", "\127\220\126\121\163\129\231\064" ; 14, 13, 20, 831, 686, "14:13:20.831686", "\081\245\043\157\026\000\233\064" ; 19, 26, 6, 212, 545, "19:26:06.212545", "\255\149\149\102\227\020\241\064" ; 22, 51, 35, 406, 21, "22:51:35.406021", "\072\224\015\127\118\023\244\064" ; 22, 29, 38, 719, 99, "22:29:38.719099", "\249\243\109\129\043\197\243\064" ; 16, 47, 46, 670, 870, "16:47:46.670870", "\188\092\196\119\085\134\237\064" ; 23, 36, 54, 318, 302, "23:36:54.318302", "\132\214\195\023\101\193\244\064" ; 19, 45, 53, 948, 368, "19:45:53.948368", "\137\236\131\044\031\095\241\064" ; 13, 10, 53, 886, 377, "13:10:53.886377", "\093\076\051\093\188\043\231\064" ; 7, 35, 27, 307, 868, "07:35:27.307868", "\223\251\027\180\211\175\218\064" ; 17, 43, 51, 236, 123, "17:43:51.236123", "\090\210\081\142\231\042\239\064" ; 17, 30, 0, 707, 130, "17:30:00.707130", "\001\024\207\160\022\195\238\064" ; 21, 14, 30, 848, 245, "21:14:30.848245", "\096\089\105\146\109\171\242\064" ; 8, 45, 6, 459, 409, "08:45:06.459409", "\159\001\245\102\157\196\222\064" ; 7, 35, 55, 144, 936, "07:35:55.144936", "\001\165\161\070\201\182\218\064" ; 11, 12, 32, 648, 814, "11:12:32.648814", "\230\147\021\195\020\180\227\064" ; 13, 54, 18, 971, 404, "13:54:18.971404", "\102\215\189\021\095\113\232\064" ; 14, 15, 57, 230, 317, "14:15:57.230317", "\215\193\193\094\167\019\233\064" ; 5, 5, 15, 373, 836, "05:05:15.373836", "\132\212\237\236\215\226\209\064" ; 11, 41, 35, 624, 740, "11:41:35.624740", "\145\189\222\253\243\141\228\064" ; 15, 50, 55, 13, 768, "15:50:55.013768", "\183\150\201\112\224\219\235\064" ; 12, 55, 58, 132, 167, "12:55:58.132167", "\211\073\182\058\196\187\230\064" ; 19, 34, 25, 506, 48, "19:34:25.506048", "\163\201\197\024\024\052\241\064" ; 17, 30, 5, 307, 541, "17:30:05.307541", "\038\057\096\215\169\195\238\064" ; 12, 51, 52, 177, 6, "12:51:52.177006", "\167\124\008\170\005\157\230\064" ; 6, 56, 50, 896, 824, "06:56:50.896824", "\145\125\144\101\185\108\216\064" ; 17, 5, 1, 507, 57, "17:05:01.507057", "\006\154\207\057\176\007\238\064" ; 4, 56, 4, 340, 845, "04:56:04.340845", "\000\140\103\208\021\089\209\064" ; 13, 10, 52, 178, 38, "13:10:52.178038", "\110\191\124\178\133\043\231\064" ; 21, 33, 53, 416, 680, "21:33:53.416680", "\206\165\184\170\022\244\242\064" ; 21, 36, 41, 140, 310, "21:36:41.140310", "\213\178\181\062\146\254\242\064" ; 20, 52, 35, 756, 734, "20:52:35.756734", "\092\028\149\027\060\089\242\064" ; 17, 49, 26, 392, 799, "17:49:26.392799", "\093\053\207\145\204\084\239\064" ; 18, 59, 40, 819, 62, "18:59:40.819062", "\119\193\224\026\205\177\240\064" ; 12, 21, 26, 29, 473, "12:21:26.029473", "\100\092\113\241\192\184\229\064" ; 8, 25, 10, 643, 583, "08:25:10.643583", "\081\192\118\048\169\153\221\064" ; 17, 4, 20, 530, 44, "17:04:20.530044", "\174\213\030\246\144\002\238\064" ; 14, 59, 50, 22, 233, "14:59:50.022233", "\252\250\033\182\192\092\234\064" ; 11, 17, 39, 989, 885, "11:17:39.989885", "\186\078\035\173\127\218\227\064" ; 4, 6, 28, 268, 665, "04:06:28.268665", "\074\094\157\099\034\226\204\064" ; 14, 52, 29, 62, 596, "14:52:29.062596", "\155\083\201\000\162\037\234\064" ; 7, 11, 37, 647, 376, "07:11:37.647376", "\014\191\155\110\105\074\217\064" ; 9, 34, 35, 296, 293, "09:34:35.296293", "\033\117\059\123\105\213\224\064" ; 9, 13, 58, 124, 361, "09:13:58.124361", "\125\235\195\250\195\058\224\064" ; 16, 20, 18, 720, 248, "16:20:18.720248", "\160\136\069\012\087\184\236\064" ; 13, 5, 47, 644, 375, "13:05:47.644375", "\236\081\184\158\116\005\231\064" ; 18, 4, 21, 84, 600, "18:04:21.084600", "\040\015\011\181\162\196\239\064" ; 9, 48, 46, 8, 770, "09:48:46.008770", "\230\005\216\071\192\063\225\064" ; 14, 15, 2, 705, 106, "14:15:02.705106", "\071\117\058\144\214\012\233\064" ; 21, 8, 3, 485, 562, "21:08:03.485562", "\227\168\220\196\055\147\242\064" ; 18, 22, 11, 509, 267, "18:22:11.509267", "\095\039\245\037\056\037\240\064" ; 12, 9, 6, 84, 891, "12:09:06.084891", "\152\084\109\183\066\092\229\064" ; 3, 10, 32, 188, 67, "03:10:32.188067", "\059\087\148\018\024\084\198\064" ; 17, 57, 1, 200, 871, "17:57:01.200871", "\246\004\137\109\166\141\239\064" ; 15, 30, 47, 441, 538, "15:30:47.441538", "\190\076\020\033\238\068\235\064" ; 22, 44, 2, 518, 415, "22:44:02.518415", "\236\134\109\075\040\251\243\064" ; 5, 1, 19, 134, 655, "05:01:19.134655", "\079\001\048\158\200\167\209\064" ; 11, 27, 21, 990, 485, "11:27:21.990485", "\069\153\013\178\063\035\228\064" ; 22, 39, 48, 960, 752, "22:39:48.960752", "\058\125\061\095\079\235\243\064" ; 21, 55, 15, 443, 816, "21:55:15.443816", "\087\206\222\025\055\068\243\064" ; 13, 10, 53, 411, 939, "13:10:53.411939", "\158\178\154\046\173\043\231\064" ; 11, 28, 37, 758, 639, "11:28:37.758639", "\207\075\197\070\184\044\228\064" ; 3, 42, 48, 376, 931, "03:42:48.376931", "\237\102\070\063\048\028\202\064" ; 7, 26, 0, 41, 467, "07:26:00.041467", "\056\052\101\167\002\034\218\064" ; 6, 53, 52, 723, 497, "06:53:52.723497", "\113\092\198\077\046\064\216\064" ; 8, 45, 57, 156, 746, "08:45:57.156746", "\242\095\032\008\074\209\222\064" ; 4, 49, 24, 1, 664, "04:49:24.001664", "\101\082\067\027\000\245\208\064" ; 5, 47, 28, 137, 200, "05:47:28.137200", "\064\130\226\199\008\092\212\064" ; 15, 20, 30, 934, 235, "15:20:30.934235", "\121\204\064\229\221\247\234\064" ; 2, 13, 10, 621, 708, "02:13:10.621708", "\169\103\065\040\159\054\191\064" ; 7, 27, 24, 109, 210, "07:27:24.109210", "\153\240\075\253\006\055\218\064" ; 9, 35, 25, 286, 690, "09:35:25.286690", "\195\129\144\044\169\219\224\064" ; 12, 15, 18, 950, 757, "12:15:18.950757", "\174\241\153\108\222\138\229\064" ; 19, 17, 14, 447, 629, "19:17:14.447629", "\188\006\125\041\167\243\240\064" ; 6, 51, 45, 227, 902, "06:51:45.227902", "\044\069\242\149\078\032\216\064" ; 16, 33, 38, 190, 94, "16:33:38.190094", "\038\003\064\021\070\028\237\064" ; 20, 11, 12, 899, 784, "20:11:12.899784", "\088\232\131\101\014\190\241\064" ; 8, 31, 59, 167, 597, "08:31:59.167597", "\122\196\232\185\202\255\221\064" ; 16, 28, 40, 407, 903, "16:28:40.407903", "\158\151\138\013\013\247\236\064" ; 11, 3, 33, 679, 191, "11:03:33.679191", "\151\195\238\187\181\112\227\064" ; 16, 27, 56, 739, 327, "16:27:56.739327", "\194\024\145\168\151\241\236\064" ; 17, 28, 4, 702, 403, "17:28:04.702403", "\051\219\021\122\150\180\238\064" ; 19, 12, 47, 691, 314, "19:12:47.691314", "\213\068\159\015\251\226\240\064" ; 20, 12, 17, 759, 18, "20:12:17.759018", "\242\014\240\036\028\194\241\064" ; 21, 47, 48, 498, 900, "21:47:48.498900", "\000\145\126\251\071\040\243\064" ; 1, 52, 34, 13, 113, "01:52:34.013113", "\039\162\095\091\003\098\186\064" ; 17, 21, 33, 828, 625, "17:21:33.828625", "\117\147\024\132\186\131\238\064" ; 20, 26, 29, 457, 150, "20:26:29.457150", "\182\132\124\080\087\247\241\064" ; 21, 56, 1, 21, 692, "21:56:01.021692", "\233\181\217\088\016\071\243\064" ; 13, 19, 31, 421, 747, "13:19:31.421747", "\134\144\243\126\109\108\231\064" ; 21, 22, 7, 881, 374, "21:22:07.881374", "\152\159\027\026\254\199\242\064" ; 20, 59, 4, 552, 828, "20:59:04.552828", "\069\044\098\216\136\113\242\064" ; 17, 42, 14, 894, 198, "17:42:14.894198", "\197\031\069\157\220\030\239\064" ; 1, 50, 49, 823, 795, "01:50:49.823795", "\156\167\058\228\210\249\185\064" ; 15, 8, 21, 450, 513, "15:08:21.450513", "\045\061\154\106\174\156\234\064" ; 6, 46, 54, 369, 860, "06:46:54.369860", "\006\071\201\171\151\215\215\064" ; 23, 44, 25, 410, 102, "23:44:25.410102", "\097\029\199\143\150\221\244\064" ; 17, 54, 32, 473, 76, "17:54:32.473076", "\144\071\112\035\015\123\239\064" ; 0, 37, 26, 180, 486, "00:37:26.180486", "\197\054\169\104\092\140\161\064" ; 20, 12, 33, 593, 567, "20:12:33.593567", "\079\028\064\127\025\195\241\064" ; 18, 24, 24, 569, 159, "18:24:24.569159", "\180\119\070\027\137\045\240\064" ; 22, 22, 10, 404, 831, "22:22:10.404831", "\022\018\048\122\038\169\243\064" ; 15, 50, 19, 759, 751, "15:50:19.759751", "\067\084\225\079\120\215\235\064" ; 17, 31, 17, 546, 171, "17:31:17.546171", "\225\154\059\122\177\204\238\064" ; 11, 38, 47, 446, 989, "11:38:47.446989", "\022\224\187\077\238\120\228\064" ; 3, 11, 55, 122, 155, "03:11:55.122155", "\005\105\198\162\143\125\198\064" ; 22, 57, 36, 219, 744, "22:57:36.219744", "\216\072\018\132\003\046\244\064" ; 3, 23, 19, 986, 320, "03:23:19.986320", "\178\215\187\063\254\211\199\064" ; 7, 49, 14, 313, 187, "07:49:14.313187", "\162\124\065\011\148\126\219\064" ; 12, 59, 12, 739, 973, "12:59:12.739973", "\094\219\219\173\023\212\230\064" ; 8, 26, 25, 52, 642, "08:26:25.052642", "\025\141\124\094\067\172\221\064" ; 7, 40, 13, 925, 871, "07:40:13.925871", "\084\112\120\065\123\247\218\064" ; 3, 21, 42, 396, 875, "03:21:42.396875", "\205\204\204\204\050\163\199\064" ; 18, 0, 54, 753, 797, "18:00:54.753797", "\218\226\026\031\216\170\239\064" ; 1, 48, 0, 369, 234, "01:48:00.369234", "\146\146\030\134\094\080\185\064" ; 17, 24, 8, 120, 91, "17:24:08.120091", "\178\020\201\215\003\151\238\064" ; 11, 5, 26, 221, 184, "11:05:26.221184", "\204\119\240\019\199\126\227\064" ; 15, 47, 49, 113, 977, "15:47:49.113977", "\240\023\179\165\163\196\235\064" ; 15, 27, 24, 152, 6, "15:27:24.152006", "\218\175\059\221\132\043\235\064" ; 20, 32, 23, 932, 603, "20:32:23.932603", "\146\031\241\235\126\013\242\064" ; 12, 0, 2, 216, 339, "12:00:02.216339", "\059\196\063\236\070\024\229\064" ; 19, 16, 21, 902, 827, "19:16:21.902827", "\111\185\250\113\094\240\240\064" ; 2, 53, 12, 191, 390, "02:53:12.191390", "\100\175\119\127\024\076\196\064" ; 4, 45, 33, 31, 411, "04:45:33.031411", "\111\072\163\002\066\187\208\064" ; 23, 4, 44, 452, 493, "23:04:44.452493", "\203\076\105\061\199\072\244\064" ; 18, 44, 8, 139, 472, "18:44:08.139472", "\235\253\070\059\130\119\240\064" ; 18, 3, 37, 911, 225, "18:03:37.911225", "\202\084\193\040\061\191\239\064" ; 6, 6, 7, 825, 706, "06:06:07.825706", "\135\250\093\216\244\115\213\064" ; 9, 33, 13, 164, 135, "09:33:13.164135", "\036\011\152\064\037\203\224\064" ; 11, 48, 0, 139, 176, "11:48:00.139176", "\013\058\033\116\004\190\228\064" ; 3, 32, 24, 287, 996, "03:32:24.287996", "\177\140\013\221\036\228\200\064" ; 22, 18, 49, 462, 659, "22:18:49.462659", "\163\031\013\103\151\156\243\064" ; 18, 12, 12, 830, 481, "18:12:12.830481", "\223\227\076\147\154\255\239\064" ; 19, 53, 35, 902, 996, "19:53:35.902996", "\007\239\171\114\254\123\241\064" ; 22, 4, 2, 435, 406, "22:04:02.435406", "\040\072\108\247\038\101\243\064" ; 0, 52, 7, 536, 519, "00:52:07.536519", "\094\077\158\178\018\111\168\064" ; 21, 26, 36, 160, 161, "21:26:36.160161", "\018\251\004\144\194\216\242\064" ; 3, 58, 46, 814, 889, "03:58:46.814889", "\112\098\072\078\104\251\203\064" ; 23, 7, 27, 949, 776, "23:07:27.949776", "\168\081\072\050\255\082\244\064" ; 19, 10, 32, 895, 713, "19:10:32.895713", "\154\039\215\084\142\218\240\064" ; 10, 56, 15, 936, 889, "10:56:15.936889", "\224\163\254\250\253\057\227\064" ; 5, 40, 32, 583, 59, "05:40:32.583059", "\041\178\214\080\037\244\211\064" ; 4, 36, 4, 266, 215, "04:36:04.266215", "\173\163\170\009\017\045\208\064" ; 4, 28, 51, 1, 370, "04:28:51.001370", "\153\100\228\044\128\129\207\064" ; 4, 20, 1, 228, 575, "04:20:01.228575", "\215\018\242\065\157\120\206\064" ; 2, 45, 25, 118, 605, "02:45:25.118605", "\018\218\114\046\143\098\195\064" ; 10, 6, 15, 645, 65, "10:06:15.645065", "\217\090\095\164\244\194\225\064" ; 8, 28, 34, 787, 750, "08:28:34.787750", "\219\249\126\106\178\204\221\064" ; 11, 20, 39, 66, 456, "11:20:39.066456", "\084\085\104\032\226\240\227\064" ; 15, 41, 47, 853, 922, "15:41:47.853922", "\235\058\084\083\123\151\235\064" ; 4, 42, 56, 355, 622, "04:42:56.355622", "\239\198\130\194\022\148\208\064" ; 1, 35, 21, 970, 87, "01:35:21.970087", "\071\035\159\087\248\089\182\064" ; 3, 1, 27, 142, 168, "03:01:27.142168", "\069\159\143\050\146\067\197\064" ; 16, 36, 50, 239, 541, "16:36:50.239541", "\034\227\081\170\071\052\237\064" ; 12, 58, 58, 522, 820, "12:58:58.522820", "\054\002\241\186\080\210\230\064" ; 9, 8, 12, 56, 674, "09:08:12.056674", "\017\254\069\208\129\015\224\064" ; 9, 19, 12, 566, 650, "09:19:12.566650", "\073\046\255\033\018\098\224\064" ; 3, 49, 42, 547, 825, "03:49:42.547825", "\119\045\033\031\070\235\202\064" ; 15, 30, 13, 247, 830, "15:30:13.247830", "\031\046\057\238\167\064\235\064" ; 16, 34, 0, 995, 54, "16:34:00.995054", "\120\124\123\215\031\031\237\064" ; 7, 40, 53, 854, 191, "07:40:53.854191", "\098\186\016\171\118\001\219\064" ; 8, 52, 3, 326, 958, "08:52:03.326958", "\075\063\225\236\212\044\223\064" ; 7, 0, 9, 539, 168, "07:00:09.539168", "\195\127\186\129\098\158\216\064" ; 7, 48, 20, 887, 904, "07:48:20.887904", "\127\076\107\211\056\113\219\064" ; 12, 3, 21, 909, 562, "12:03:21.909562", "\118\196\033\027\061\049\229\064" ; 16, 11, 21, 262, 332, "16:11:21.262332", "\023\020\006\101\040\117\236\064" ; 14, 24, 40, 851, 715, "14:24:40.851715", "\209\208\063\065\027\085\233\064" ; 16, 24, 42, 496, 864, "16:24:42.496864", "\210\084\079\230\079\217\236\064" ; 5, 33, 50, 539, 848, "05:33:50.539848", "\052\160\222\140\162\143\211\064" ; 18, 35, 54, 551, 374, "18:35:54.551374", "\030\139\109\210\168\088\240\064" ; 19, 20, 28, 295, 19, "19:20:28.295019", "\203\215\101\184\196\255\240\064" ; 23, 47, 12, 602, 356, "23:47:12.602356", "\137\011\064\163\009\232\244\064" ; 12, 19, 26, 622, 266, "12:19:26.622266", "\238\098\154\233\211\169\229\064" ; 11, 42, 24, 868, 18, "11:42:24.868018", "\075\175\205\198\027\148\228\064" ; 22, 4, 45, 276, 979, "22:04:45.276979", "\043\136\129\110\212\103\243\064" ; 7, 28, 29, 765, 751, "07:28:29.765751", "\120\123\016\002\113\071\218\064" ; 0, 30, 41, 577, 819, "00:30:41.577819", "\008\176\200\175\079\198\156\064" ; 23, 52, 28, 324, 821, "23:52:28.324821", "\064\129\119\050\197\251\244\064" ; 8, 44, 41, 9, 733, "08:44:41.009733", "\044\041\119\159\064\190\222\064" ; 15, 9, 51, 924, 797, "15:09:51.924797", "\206\224\239\151\253\167\234\064" ; 8, 16, 29, 978, 626, "08:16:29.978626", "\065\242\206\161\126\023\221\064" ; 2, 32, 36, 971, 307, "02:32:36.971307", "\176\171\201\083\124\226\193\064" ; 1, 7, 36, 194, 853, "01:07:36.194853", "\014\189\197\195\099\176\175\064" ; 17, 19, 35, 378, 501, "17:19:35.378501", "\016\033\174\028\236\116\238\064" ; 9, 53, 29, 931, 825, "09:53:29.931825", "\147\169\130\209\061\099\225\064" ; 11, 15, 12, 338, 330, "11:15:12.338330", "\169\111\153\211\010\200\227\064" ; 3, 3, 12, 10, 845, "03:03:12.010845", "\042\116\094\099\001\120\197\064" ; 13, 32, 38, 361, 439, "13:32:38.361439", "\144\133\232\144\203\206\231\064" ; 18, 2, 24, 192, 367, "18:02:24.192367", "\187\214\222\039\006\182\239\064" ; 11, 7, 35, 655, 183, "11:07:35.655183", "\188\086\066\247\244\142\227\064" ; 12, 50, 22, 274, 459, "12:50:22.274459", "\163\061\094\200\200\145\230\064" ; 2, 37, 38, 226, 437, "02:37:38.226437", "\206\058\227\251\028\121\194\064" ; 15, 12, 21, 751, 20, "15:12:21.751020", "\084\024\091\008\184\186\234\064" ; 19, 8, 31, 410, 239, "19:08:31.410239", "\009\197\086\144\246\210\240\064" ; 12, 26, 25, 540, 247, "12:26:25.540247", "\153\019\180\073\049\222\229\064" ; 21, 1, 32, 475, 19, "21:01:32.475019", "\224\133\173\153\199\122\242\064" ; 10, 24, 23, 451, 675, "10:24:23.451675", "\046\033\031\116\238\074\226\064" ; 23, 53, 1, 520, 419, "23:53:01.520419", "\148\223\162\083\216\253\244\064" ; 12, 30, 10, 321, 42, "12:30:10.321042", "\085\223\249\069\074\250\229\064" ; 8, 59, 50, 643, 825, "08:59:50.643825", "\214\197\109\052\169\161\223\064" ; 22, 57, 8, 493, 299, "22:57:08.493299", "\003\126\141\228\071\044\244\064" ; 15, 2, 36, 75, 422, "15:02:36.075422", "\236\101\219\105\130\113\234\064" ; 1, 15, 1, 126, 993, "01:15:01.126993", "\210\253\156\130\032\149\177\064" ; 12, 28, 14, 635, 663, "12:28:14.635663", "\137\238\089\087\212\235\229\064" ; 18, 4, 54, 942, 204, "18:04:54.942204", "\198\000\137\038\222\200\239\064" ; 17, 8, 27, 858, 475, "17:08:27.858475", "\046\144\160\120\123\033\238\064" ; 20, 26, 7, 991, 305, "20:26:07.991305", "\181\161\098\220\255\245\241\064" ; 22, 49, 25, 156, 421, "22:49:25.156421", "\119\078\179\128\082\015\244\064" ; 12, 14, 49, 568, 161, "12:14:49.568161", "\060\250\095\046\050\135\229\064" ; 19, 10, 23, 729, 919, "19:10:23.729919", "\156\139\191\173\251\217\240\064" ; 13, 0, 40, 42, 97, "13:00:40.042097", "\200\206\219\088\001\223\230\064" ; 15, 17, 12, 870, 508, "15:17:12.870508", "\221\151\051\219\027\223\234\064" ; 20, 19, 23, 170, 602, "20:19:23.170602", "\170\041\201\186\178\220\241\064" ; 1, 18, 9, 456, 770, "01:18:09.456770", "\203\243\224\238\116\081\178\064" ; 0, 54, 43, 778, 404, "00:54:43.778404", "\038\022\248\138\142\167\169\064" ; 5, 35, 28, 231, 362, "05:35:28.231362", "\226\143\162\206\014\168\211\064" ; 8, 3, 47, 384, 395, "08:03:47.384395", "\111\124\237\153\216\088\220\064" ; 5, 12, 38, 713, 307, "05:12:38.713307", "\064\103\210\166\173\081\210\064" ; 0, 34, 51, 835, 480, "00:34:51.835480", "\237\216\008\196\171\087\160\064" ; 3, 45, 26, 912, 408, "03:45:26.912408", "\078\012\201\201\116\107\202\064" ; 10, 34, 3, 471, 434, "10:34:03.471434", "\135\193\252\021\111\147\226\064" ; 7, 11, 47, 385, 883, "07:11:47.385883", "\069\156\078\178\216\076\217\064" ; 11, 51, 56, 864, 684, "11:51:56.864684", "\172\199\125\171\155\219\228\064" ; 7, 19, 19, 733, 964, "07:19:19.733964", "\028\036\068\249\238\189\217\064" ; 6, 42, 55, 197, 25, "06:42:55.197025", "\224\190\014\156\204\155\215\064" ; 3, 8, 44, 888, 712, "03:08:44.888712", "\200\151\080\193\113\030\198\064" ; 5, 45, 35, 841, 426, "05:45:35.841426", "\000\112\236\217\245\063\212\064" ; 14, 43, 12, 634, 877, "14:43:12.634877", "\255\145\233\080\020\224\233\064" ; 20, 57, 10, 5, 821, "20:57:10.005821", "\202\194\215\023\096\106\242\064" ; 3, 26, 26, 891, 270, "03:26:26.891270", "\244\166\034\021\114\049\200\064" ; 20, 42, 19, 849, 448, "20:42:19.849448", "\059\201\086\151\189\050\242\064" ; 10, 56, 52, 526, 870, "10:56:52.526870", "\104\121\030\220\144\062\227\064" ; 15, 17, 31, 12, 559, "15:17:31.012559", "\201\033\226\102\096\225\234\064" ; 12, 30, 6, 471, 825, "12:30:06.471825", "\014\190\048\025\207\249\229\064" ; 7, 7, 48, 855, 280, "07:07:48.855280", "\059\083\232\188\054\017\217\064" ; 9, 33, 18, 462, 319, "09:33:18.462319", "\042\055\081\203\206\203\224\064" ; 7, 39, 33, 376, 262, "07:39:33.376262", "\047\054\173\020\088\237\218\064" ; 15, 54, 43, 905, 336, "15:54:43.905336", "\252\051\131\248\124\248\235\064" ; 14, 42, 1, 459, 874, "14:42:01.459874", "\201\173\073\183\046\215\233\064" ; 21, 29, 24, 919, 811, "21:29:24.919811", "\056\189\139\183\078\227\242\064" ; 9, 10, 6, 330, 252, "09:10:06.330252", "\110\164\108\145\202\029\224\064" ; 22, 53, 59, 211, 178, "22:53:59.211178", "\186\046\252\096\115\032\244\064" ; 22, 17, 32, 434, 473, "22:17:32.434473", "\223\245\153\243\198\151\243\064" ; 13, 27, 23, 986, 36, "13:27:23.986036", "\149\094\155\141\127\167\231\064" ; 10, 43, 22, 39, 110, "10:43:22.039110", "\094\157\099\064\065\217\226\064" ; 19, 35, 2, 494, 653, "19:35:02.494653", "\158\067\025\234\103\054\241\064" ; 4, 32, 37, 435, 74, "04:32:37.435074", "\171\060\129\176\183\242\207\064" ; 6, 34, 9, 681, 839, "06:34:09.681839", "\137\011\064\163\107\024\215\064" ; 11, 2, 44, 185, 990, "11:02:44.185990", "\236\076\161\243\133\106\227\064" ; 23, 5, 23, 600, 514, "23:05:23.600514", "\109\145\180\155\057\075\244\064" ; 22, 59, 52, 764, 335, "22:59:52.764335", "\067\086\183\058\140\054\244\064" ; 22, 39, 3, 469, 800, "22:39:03.469800", "\058\001\077\132\119\232\243\064" ; 19, 47, 5, 268, 323, "19:47:05.268323", "\220\014\013\075\148\099\241\064" ; 22, 34, 24, 223, 207, "22:34:24.223207", "\212\128\065\146\003\215\243\064" ; 2, 33, 34, 110, 97, "02:33:34.110097", "\050\147\168\023\014\255\193\064" ; 23, 49, 32, 162, 363, "23:49:32.162363", "\241\241\009\153\194\240\244\064" ; 11, 6, 33, 518, 1, "11:06:33.518001", "\073\213\118\147\048\135\227\064" ; 18, 46, 46, 215, 506, "18:46:46.215506", "\097\107\182\114\099\129\240\064" ; 13, 28, 10, 185, 972, "13:28:10.185972", "\063\141\123\243\069\173\231\064" ; 20, 12, 14, 115, 595, "20:12:14.115595", "\138\036\122\217\225\193\241\064" ; 13, 57, 32, 557, 17, "13:57:32.557017", "\202\080\021\211\145\137\232\064" ; 22, 3, 3, 927, 563, "22:03:03.927563", "\223\076\076\215\126\097\243\064" ; 10, 48, 49, 61, 920, "10:48:49.061920", "\223\166\063\251\033\002\227\064" ; 19, 34, 19, 112, 686, "19:34:19.112686", "\203\213\143\205\177\051\241\064" ; 15, 32, 24, 291, 234, "15:32:24.291234", "\047\247\201\081\009\081\235\064" ; 8, 30, 11, 376, 904, "08:30:11.376904", "\111\244\049\031\216\228\221\064" ; 3, 35, 31, 583, 103, "03:35:31.583103", "\154\125\030\163\202\065\201\064" ; 22, 18, 6, 433, 288, "22:18:06.433288", "\220\101\191\238\230\153\243\064" ; 9, 20, 53, 938, 741, "09:20:53.938741", "\206\144\042\010\190\110\224\064" ; 15, 27, 16, 829, 110, "15:27:16.829110", "\217\177\017\136\154\042\235\064" ; 8, 55, 41, 280, 237, "08:55:41.280237", "\136\043\103\239\081\099\223\064" ; 15, 18, 3, 876, 202, "15:18:03.876202", "\214\198\216\009\124\229\234\064" ; 10, 13, 1, 103, 635, "10:13:01.103635", "\247\088\250\080\163\245\225\064" ; 15, 38, 35, 453, 631, "15:38:35.453631", "\175\040\037\132\110\127\235\064" ; 1, 34, 28, 838, 998, "01:34:28.838998", "\105\171\146\200\214\036\182\064" ; 4, 23, 58, 354, 261, "04:23:58.354261", "\159\168\108\088\045\239\206\064" ; 13, 29, 22, 629, 962, "13:29:22.629962", "\119\017\166\040\084\182\231\064" ; 20, 46, 30, 371, 782, "20:46:30.371782", "\180\174\209\242\101\066\242\064" ; 17, 32, 14, 596, 430, "17:32:14.596430", "\011\094\244\021\211\211\238\064" ; 22, 16, 14, 68, 640, "22:16:14.068640", "\179\065\038\025\225\146\243\064" ; 10, 45, 55, 187, 151, "10:45:55.187151", "\013\024\036\253\101\236\226\064" ; 10, 32, 29, 131, 256, "10:32:29.131256", "\109\200\063\051\164\135\226\064" ; 9, 45, 1, 180, 913, "09:45:01.180913", "\078\015\010\202\165\035\225\064" ; 16, 38, 41, 524, 603, "16:38:41.524603", "\012\059\140\201\048\066\237\064" ; 16, 58, 4, 633, 133, "16:58:04.633133", "\033\035\160\066\148\211\237\064" ; 9, 57, 54, 319, 774, "09:57:54.319774", "\004\175\150\059\074\132\225\064" ; 16, 44, 15, 829, 799, "16:44:15.829799", "\232\161\182\141\250\107\237\064" ; 3, 0, 18, 62, 46, "03:00:18.062046", "\108\146\031\241\007\033\197\064" ; 6, 0, 53, 312, 498, "06:00:53.312498", "\133\156\247\255\083\037\213\064" ; 16, 4, 23, 723, 875, "16:04:23.723875", "\108\231\251\041\247\064\236\064" ; 19, 59, 16, 819, 322, "19:59:16.819322", "\175\098\241\027\077\145\241\064" ; 18, 13, 27, 303, 406, "18:13:27.303406", "\247\063\192\218\116\004\240\064" ; 11, 11, 28, 180, 931, "11:11:28.180931", "\251\206\047\202\005\172\227\064" ; 3, 1, 30, 559, 638, "03:01:30.559638", "\204\205\055\162\071\069\197\064" ; 5, 44, 12, 357, 588, "05:44:12.357588", "\092\199\184\226\022\043\212\064" ; 14, 2, 26, 60, 301, "14:02:26.060301", "\221\092\252\237\065\174\232\064" ; 10, 20, 32, 612, 136, "10:20:32.612136", "\151\060\158\150\019\046\226\064" ; 22, 48, 18, 418, 667, "22:48:18.418667", "\015\043\220\178\038\011\244\064" ; 18, 40, 1, 153, 11, "18:40:01.153011", "\143\169\187\114\018\104\240\064" ; 21, 42, 57, 199, 776, "21:42:57.199776", "\168\081\072\050\019\022\243\064" ; 17, 37, 1, 422, 14, "17:37:01.422014", "\014\129\035\129\173\247\238\064" ; 16, 47, 52, 428, 115, "16:47:52.428115", "\126\058\030\179\013\135\237\064" ; 17, 36, 30, 523, 168, "17:36:30.523168", "\074\209\202\189\208\243\238\064" ; 9, 38, 17, 753, 688, "09:38:17.753688", "\236\075\054\030\056\241\224\064" ; 11, 15, 10, 638, 898, "11:15:10.638898", "\239\055\218\113\212\199\227\064" ; 15, 49, 17, 210, 442, "15:49:17.210442", "\118\220\240\187\166\207\235\064" ; 16, 56, 8, 371, 404, "16:56:08.371404", "\051\164\138\226\011\197\237\064" ; 3, 19, 10, 232, 1, "03:19:10.232001", "\210\113\053\178\029\087\199\064" ; 15, 10, 50, 778, 741, "15:10:50.778741", "\226\062\114\235\088\175\234\064" ; 5, 7, 30, 831, 249, "05:07:30.831249", "\117\001\047\051\181\004\210\064" ; 9, 3, 7, 691, 744, "09:03:07.691744", "\077\160\136\069\236\210\223\064" ; 9, 4, 4, 14, 712, "09:04:04.014712", "\183\153\010\241\000\225\223\064" ; 19, 58, 43, 148, 860, "19:58:43.148860", "\251\005\187\097\050\143\241\064" ; 1, 30, 59, 577, 426, "01:30:59.577426", "\220\185\048\210\147\083\181\064" ; 13, 24, 28, 714, 417, "13:24:28.714417", "\087\010\129\220\150\145\231\064" ; 16, 37, 42, 956, 589, "16:37:42.956589", "\215\136\096\156\222\058\237\064" ; 8, 27, 59, 141, 65, "08:27:59.141065", "\103\126\053\007\201\195\221\064" ; 14, 1, 8, 727, 972, "14:01:08.727972", "\141\239\139\075\151\164\232\064" ; 5, 51, 12, 109, 395, "05:51:12.109395", "\214\226\083\000\007\148\212\064" ; 17, 22, 52, 930, 399, "17:22:52.930399", "\167\031\212\197\157\141\238\064" ; 0, 27, 57, 399, 562, "00:27:57.399562", "\229\234\199\038\153\053\154\064" ; 0, 46, 22, 800, 993, "00:46:22.800993", "\167\038\193\027\154\189\165\064" ; 8, 36, 14, 16, 456, "08:36:14.016456", "\117\119\157\013\129\063\222\064" ; 23, 47, 17, 175, 124, "23:47:17.175124", "\204\210\078\205\082\232\244\064" ; 22, 53, 45, 647, 677, "22:53:45.647677", "\214\142\226\092\154\031\244\064" ; 6, 41, 50, 182, 667, "06:41:50.182667", "\196\237\208\176\139\139\215\064" ; 0, 58, 33, 949, 373, "00:58:33.949373", "\105\197\055\020\230\115\171\064" ; 17, 13, 52, 523, 544, "17:13:52.523544", "\193\088\223\192\016\074\238\064" ; 15, 3, 23, 171, 157, "15:03:23.171157", "\176\062\030\122\101\119\234\064" ; 2, 53, 4, 494, 23, "02:53:04.494023", "\061\074\037\060\063\072\196\064" ; 17, 25, 41, 787, 100, "17:25:41.787100", "\213\086\236\047\185\162\238\064" ; 8, 55, 11, 997, 750, "08:55:11.997750", "\229\208\034\219\255\091\223\064" ; 7, 30, 25, 229, 954, "07:30:25.229954", "\101\251\144\183\078\100\218\064" ; 22, 15, 47, 38, 655, "22:15:47.038655", "\141\180\084\158\048\145\243\064" ; 16, 43, 48, 197, 934, "16:43:48.197934", "\025\175\121\085\134\104\237\064" ; 17, 51, 34, 816, 885, "17:51:34.816885", "\243\002\236\035\218\100\239\064" ; 15, 59, 44, 272, 652, "15:59:44.272652", "\230\175\144\185\008\030\236\064" ; 21, 15, 39, 718, 280, "21:15:39.718280", "\085\043\019\126\187\175\242\064" ; 21, 8, 25, 395, 253, "21:08:25.395253", "\075\207\244\082\150\148\242\064" ; 22, 12, 54, 151, 644, "22:12:54.151644", "\074\066\034\109\098\134\243\064" ; 6, 17, 22, 550, 563, "06:17:22.550563", "\217\151\108\060\163\028\214\064" ; 11, 50, 15, 439, 389, "11:50:15.439389", "\039\133\121\015\238\206\228\064" ; 16, 1, 59, 506, 867, "16:01:59.506867", "\142\036\065\056\240\046\236\064" ; 3, 21, 38, 361, 132, "03:21:38.361132", "\197\200\146\057\046\161\199\064" ; 18, 27, 3, 992, 81, "18:27:03.992081", "\160\083\144\223\127\055\240\064" ; 18, 46, 41, 380, 537, "18:46:41.380537", "\031\247\173\022\022\129\240\064" ; 13, 54, 51, 732, 247, "13:54:51.732247", "\180\066\145\110\119\117\232\064" ; 13, 59, 52, 553, 843, "13:59:52.553843", "\132\244\020\185\017\155\232\064" ; 10, 44, 21, 572, 339, "10:44:21.572339", "\231\224\153\080\178\224\226\064" ; 16, 44, 14, 743, 605, "16:44:14.743605", "\133\182\156\203\215\107\237\064" ; 10, 46, 28, 996, 44, "10:46:28.996044", "\172\170\151\223\159\240\226\064" ; 1, 27, 0, 554, 619, "01:27:00.554619", "\190\194\130\251\141\100\180\064" ; 0, 24, 30, 456, 691, "00:24:30.456691", "\130\053\206\166\211\249\150\064" ; 15, 39, 53, 361, 333, "15:39:53.361333", "\063\057\010\144\043\137\235\064" ; 19, 7, 24, 30, 900, "19:07:24.030900", "\151\255\144\126\192\206\240\064" ; 20, 3, 29, 306, 758, "20:03:29.306758", "\156\019\123\232\020\161\241\064" ; 6, 12, 14, 825, 268, "06:12:14.825268", "\156\223\048\209\180\207\213\064" ; 5, 37, 12, 932, 634, "05:37:12.932634", "\073\132\070\176\059\194\211\064" ; 8, 29, 4, 46, 700, "08:29:04.046700", "\046\255\033\253\002\212\221\064" ; 2, 57, 39, 74, 839, "02:57:39.074839", "\188\008\083\148\137\209\196\064" ; 15, 14, 49, 597, 912, "15:14:49.597912", "\189\088\024\034\051\205\234\064" ; 12, 20, 44, 427, 275, "12:20:44.427275", "\237\158\060\172\141\179\229\064" ; 3, 3, 57, 552, 295, "03:03:57.552295", "\095\065\154\177\198\142\197\064" ; 10, 47, 51, 47, 951, "10:47:51.047951", "\026\137\208\136\225\250\226\064" ; 20, 0, 19, 86, 574, "20:00:19.086574", "\043\107\155\098\049\149\241\064" ; 2, 8, 29, 221, 869, "02:08:29.221869", "\255\034\104\204\056\029\190\064" ; 7, 15, 25, 381, 625, "07:15:25.381625", "\150\067\139\108\088\131\217\064" ; 3, 23, 5, 897, 744, "03:23:05.897744", "\024\128\070\233\242\204\199\064" ; 8, 5, 55, 425, 639, "08:05:55.425639", "\058\092\171\061\219\120\220\064" ; 6, 35, 53, 966, 447, "06:35:53.966447", "\148\132\068\218\125\050\215\064" ; 8, 8, 46, 479, 182, "08:08:46.479182", "\181\250\234\170\158\163\220\064" ; 21, 54, 5, 521, 808, "21:54:05.521808", "\108\088\083\089\216\063\243\064" ; 20, 39, 5, 418, 816, "20:39:05.418816", "\241\103\120\179\150\038\242\064" ; 13, 49, 50, 904, 617, "13:49:50.904617", "\205\089\159\242\220\079\232\064" ; 7, 22, 55, 651, 472, "07:22:55.651472", "\145\157\183\177\233\243\217\064" ; 3, 58, 41, 927, 354, "03:58:41.927354", "\232\046\137\179\246\248\203\064" ; 2, 19, 37, 274, 290, "02:19:37.274290", "\207\073\239\027\163\092\192\064" ; 8, 6, 25, 474, 922, "08:06:25.474922", "\137\062\031\101\094\128\220\064" ; 19, 1, 41, 50, 275, "19:01:41.050275", "\141\040\237\205\080\185\240\064" ; 0, 44, 26, 635, 21, "00:44:26.635021", "\140\246\120\033\069\213\164\064" ; 22, 31, 21, 842, 433, "22:31:21.842433", "\129\006\155\122\157\203\243\064" ; 19, 26, 20, 635, 432, "19:26:20.635432", "\173\190\186\042\202\021\241\064" ; 12, 49, 45, 380, 771, "12:49:45.380771", "\008\170\070\047\044\141\230\064" ; 14, 0, 20, 621, 748, "14:00:20.621748", "\203\015\092\229\147\158\232\064" ; 4, 21, 36, 795, 679, "04:21:36.795679", "\143\057\207\216\101\168\206\064" ; 8, 57, 59, 36, 40, "08:57:59.036040", "\086\183\122\078\194\133\223\064" ; 20, 19, 51, 852, 898, "20:19:51.852898", "\141\095\120\165\125\222\241\064" ; 0, 46, 57, 715, 57, "00:46:57.715057", "\142\123\243\027\110\003\166\064" ; 16, 44, 6, 172, 758, "16:44:06.172758", "\004\201\059\135\197\106\237\064" ; 10, 46, 44, 354, 952, "10:46:44.354952", "\245\075\196\091\139\242\226\064" ; 21, 58, 6, 346, 979, "21:58:06.346979", "\023\218\057\141\229\078\243\064" ; 6, 39, 30, 729, 936, "06:39:30.729936", "\011\124\069\183\174\104\215\064" ; 17, 6, 2, 85, 391, "17:06:02.085391", "\012\232\133\187\066\015\238\064" ; 11, 19, 17, 897, 610, "11:19:17.897610", "\082\155\056\185\188\230\227\064" ; 15, 59, 28, 957, 68, "15:59:28.957068", "\002\018\077\160\030\028\236\064" ; 3, 49, 3, 979, 247, "03:49:03.979247", "\218\055\247\087\253\215\202\064" ; 17, 24, 45, 981, 598, "17:24:45.981598", "\122\053\064\105\191\155\238\064" ; 7, 32, 53, 631, 419, "07:32:53.631419", "\197\060\043\105\104\137\218\064" ; 11, 35, 7, 534, 456, "11:35:07.534456", "\037\120\067\026\113\093\228\064" ; 0, 28, 48, 8, 227, "00:28:48.008227", "\199\159\168\108\008\000\155\064" ; 0, 4, 7, 468, 752, "00:04:07.468752", "\232\189\049\004\000\239\110\064" ; 16, 56, 35, 457, 502, "16:56:35.457502", "\252\059\219\163\110\200\237\064" ; 6, 0, 9, 71, 819, "06:00:09.071819", "\015\184\174\152\068\026\213\064" ; 20, 11, 49, 857, 144, "20:11:49.857144", "\128\160\220\182\093\192\241\064" ; 11, 46, 16, 443, 818, "11:46:16.443818", "\108\206\193\051\014\177\228\064" ; 8, 21, 14, 401, 97, "08:21:14.401097", "\098\192\146\171\153\094\221\064" ; 7, 57, 33, 534, 934, "07:57:33.534934", "\225\208\091\060\098\251\219\064" ; 12, 59, 13, 621, 338, "12:59:13.621338", "\184\058\000\226\051\212\230\064" ; 7, 47, 47, 908, 375, "07:47:47.908375", "\096\229\208\034\250\104\219\064" ; 21, 21, 44, 926, 306, "21:21:44.926306", "\130\061\038\210\142\198\242\064" ; 5, 44, 43, 365, 750, "05:44:43.365750", "\033\176\114\104\215\050\212\064" ; 5, 22, 35, 606, 431, "05:22:35.606431", "\018\248\195\207\230\230\210\064" ; 21, 19, 59, 483, 144, "21:19:59.483144", "\244\051\245\186\247\191\242\064" ; 21, 59, 55, 597, 982, "21:59:55.597982", "\217\146\085\145\185\085\243\064" ; 18, 21, 29, 524, 760, "18:21:29.524760", "\228\189\106\101\152\034\240\064" ; 16, 11, 13, 986, 119, "16:11:13.986119", "\222\110\073\142\063\116\236\064" ; 19, 38, 56, 214, 43, "19:38:56.214043", "\079\090\184\108\003\069\241\064" ; 20, 49, 38, 497, 951, "20:49:38.497951", "\192\119\155\247\039\078\242\064" ; 7, 33, 44, 775, 601, "07:33:44.775601", "\112\096\114\163\049\150\218\064" ; 11, 27, 58, 718, 856, "11:27:58.718856", "\081\076\222\000\215\039\228\064" ; 5, 24, 55, 455, 119, "05:24:55.455119", "\051\113\171\032\221\009\211\064" ; 4, 39, 1, 756, 511, "04:39:01.756511", "\004\029\173\106\112\089\208\064" ; 8, 50, 49, 188, 312, "08:50:49.188312", "\092\198\077\013\076\026\223\064" ; 16, 5, 44, 599, 305, "16:05:44.599305", "\235\173\129\045\019\075\236\064" ; 20, 11, 34, 134, 946, "20:11:34.134946", "\012\035\189\040\098\191\241\064" ; 8, 38, 0, 750, 841, "08:38:00.750841", "\224\104\199\013\048\090\222\064" ; 23, 58, 32, 23, 361, "23:58:32.023361", "\176\200\175\095\128\018\245\064" ; 21, 55, 32, 587, 180, "21:55:32.587180", "\014\219\022\101\073\069\243\064" ; 17, 48, 49, 643, 436, "17:48:49.643436", "\034\024\007\151\052\080\239\064" ; 15, 4, 49, 187, 783, "15:04:49.187783", "\120\126\081\002\038\130\234\064" ; 10, 24, 12, 254, 171, "10:24:12.254171", "\147\056\043\034\136\073\226\064" ; 12, 29, 27, 896, 439, "12:29:27.896439", "\124\215\160\175\252\244\229\064" ; 0, 47, 6, 523, 200, "00:47:06.523200", "\137\210\222\224\011\021\166\064" ; 5, 16, 58, 378, 881, "05:16:58.378881", "\005\024\150\063\152\146\210\064" ; 20, 22, 52, 866, 349, "20:22:52.866349", "\222\196\144\220\205\233\241\064" ; 12, 58, 12, 316, 930, "12:58:12.316930", "\036\098\074\036\138\204\230\064" ; 0, 25, 5, 854, 612, "00:25:05.854612", "\020\123\104\031\107\135\151\064" ; 3, 38, 16, 945, 321, "03:38:16.945321", "\156\077\071\000\121\148\201\064" ; 9, 53, 46, 773, 884, "09:53:46.773884", "\221\096\168\195\088\101\225\064" ; 22, 24, 45, 323, 697, "22:24:45.323697", "\205\231\220\045\213\178\243\064" ; 22, 23, 0, 847, 316, "22:23:00.847316", "\214\056\155\142\077\172\243\064" ; 5, 45, 15, 963, 930, "05:45:15.963930", "\104\116\007\177\253\058\212\064" ; 4, 8, 58, 263, 968, "04:08:58.263968", "\153\019\180\201\033\045\205\064" ; 20, 34, 52, 738, 597, "20:34:52.738597", "\127\022\075\209\203\022\242\064" ; 22, 40, 2, 403, 757, "22:40:02.403757", "\105\230\201\117\038\236\243\064" ; 9, 9, 46, 189, 386, "09:09:46.189386", "\138\058\115\015\070\027\224\064" ; 8, 54, 44, 460, 274, "08:54:44.460274", "\077\020\033\117\029\085\223\064" ; 16, 17, 37, 830, 426, "16:17:37.830426", "\248\139\217\146\058\164\236\064" ; 17, 37, 21, 651, 839, "17:37:21.651839", "\104\118\221\219\052\250\238\064" ; 22, 14, 45, 175, 300, "22:14:45.175300", "\112\095\007\206\082\141\243\064" ; 2, 14, 58, 562, 761, "02:14:58.562761", "\119\218\026\017\144\162\191\064" ; 14, 49, 58, 229, 610, "14:49:58.229610", "\027\018\247\088\199\018\234\064" ; 16, 28, 39, 216, 817, "16:28:39.216817", "\135\052\042\240\230\246\236\064" ; 6, 6, 8, 941, 184, "06:06:08.941184", "\225\208\091\060\060\116\213\064" ; 5, 39, 2, 51, 179, "05:39:02.051179", "\207\072\132\070\131\221\211\064" ; 15, 27, 30, 114, 691, "15:27:30.114691", "\197\117\140\171\067\044\235\064" ; 16, 8, 21, 437, 882, "16:08:21.437882", "\176\028\033\003\174\094\236\064" ; 12, 43, 7, 273, 237, "12:43:07.273237", "\098\133\091\190\104\091\230\064" ; 4, 37, 6, 508, 353, "04:37:06.508353", "\117\005\219\136\160\060\208\064" ; 12, 33, 31, 228, 948, "12:33:31.228948", "\144\193\138\083\103\019\230\064" ; 10, 30, 3, 690, 555, "10:30:03.690555", "\163\204\006\025\118\117\226\064" ; 6, 31, 31, 197, 18, "06:31:31.197018", "\174\098\241\155\204\240\214\064" ; 7, 24, 7, 314, 543, "07:24:07.314543", "\139\246\120\033\212\005\218\064" ; 10, 7, 38, 753, 509, "10:07:38.753509", "\007\232\190\028\088\205\225\064" ; 17, 41, 34, 810, 229, "17:41:34.810229", "\040\094\101\237\217\025\239\064" ; 15, 5, 50, 54, 759, "15:05:50.054759", "\069\242\149\192\193\137\234\064" ; 4, 37, 22, 126, 785, "04:37:22.126785", "\040\213\062\029\136\064\208\064" ; 14, 34, 38, 372, 413, "14:34:38.372413", "\244\170\206\234\203\159\233\064" ; 14, 23, 44, 473, 476, "14:23:44.473476", "\238\035\183\038\015\078\233\064" ; 19, 18, 42, 919, 480, "19:18:42.919480", "\021\169\048\182\046\249\240\064" ; 16, 7, 1, 431, 92, "16:07:01.431092", "\050\115\129\203\173\084\236\064" ; 22, 35, 51, 780, 62, "22:35:51.780062", "\174\074\034\123\124\220\243\064" ; 21, 42, 28, 107, 894, "21:42:28.107894", "\023\015\239\185\065\020\243\064" ; 21, 52, 7, 616, 230, "21:52:07.616230", "\013\253\019\220\121\056\243\064" ; 5, 29, 34, 249, 231, "05:29:34.249231", "\138\148\102\243\143\079\211\064" ; 5, 10, 28, 424, 964, "05:10:28.424964", "\126\052\156\050\027\049\210\064" ; 9, 28, 58, 47, 682, "09:28:58.047682", "\211\102\156\134\065\171\224\064" ; 21, 13, 57, 894, 416, "21:13:57.894416", "\208\038\135\079\094\169\242\064" ; 11, 53, 16, 316, 289, "11:53:16.316289", "\227\027\010\031\138\229\228\064" ; 2, 33, 32, 422, 600, "02:33:32.422600", "\165\189\193\023\054\254\193\064" ; 18, 17, 30, 566, 154, "18:17:30.566154", "\040\127\247\014\169\019\240\064" ; 20, 21, 31, 738, 764, "20:21:31.738764", "\055\051\250\209\187\228\241\064" ; 10, 57, 36, 952, 146, "10:57:36.952146", "\096\227\250\119\030\068\227\064" ; 17, 59, 58, 23, 0, "17:59:58.023000", "\250\126\106\188\192\163\239\064" ; 4, 56, 37, 935, 527, "04:56:37.935527", "\098\163\172\223\123\097\209\064" ; 2, 14, 38, 615, 870, "02:14:38.615870", "\150\004\168\169\157\142\191\064" ; 17, 4, 27, 340, 236, "17:04:27.340236", "\157\155\054\227\106\003\238\064" ; 11, 11, 15, 163, 558, "11:11:15.163558", "\160\252\221\059\101\170\227\064" ; 11, 35, 27, 549, 485, "11:35:27.549485", "\020\145\097\149\241\095\228\064" ; 22, 36, 4, 740, 411, "22:36:04.740411", "\106\052\185\216\075\221\243\064" ; 6, 59, 16, 592, 289, "06:59:16.592289", "\050\031\016\232\037\145\216\064" ; 12, 19, 8, 136, 216, "12:19:08.136216", "\038\168\225\091\132\167\229\064" ; 17, 57, 44, 524, 715, "17:57:44.524715", "\151\028\119\202\016\147\239\064" ; 16, 9, 14, 318, 641, "16:09:14.318641", "\069\156\078\050\074\101\236\064" ; 15, 24, 32, 917, 560, "15:24:32.917560", "\004\202\166\092\029\022\235\064" ; 6, 32, 46, 303, 712, "06:32:46.303712", "\218\116\004\112\147\003\215\064" ; 14, 23, 53, 512, 658, "14:23:53.512658", "\001\192\177\103\048\079\233\064" ; 21, 24, 1, 205, 867, "21:24:01.205867", "\005\050\059\075\019\207\242\064" ; 9, 14, 37, 861, 209, "09:14:37.861209", "\064\045\006\143\187\063\224\064" ; 22, 32, 15, 504, 285, "22:32:15.504285", "\238\037\141\017\248\206\243\064" ; 2, 57, 40, 763, 153, "02:57:40.763153", "\109\092\255\174\097\210\196\064" ; 4, 29, 7, 754, 764, "04:29:07.754764", "\026\084\027\156\224\137\207\064" ; 2, 57, 20, 736, 325, "02:57:20.736325", "\030\201\229\063\094\200\196\064" ; 9, 51, 44, 821, 314, "09:51:44.821314", "\056\076\052\072\026\086\225\064" ; 21, 59, 11, 430, 923, "21:59:11.430923", "\001\132\015\229\246\082\243\064" ; 17, 53, 8, 985, 565, "17:53:08.985565", "\099\156\191\137\159\112\239\064" ; 3, 10, 37, 921, 797, "03:10:37.921797", "\071\176\113\253\245\086\198\064" ; 13, 54, 30, 274, 568, "13:54:30.274568", "\145\212\066\201\200\114\232\064" ; 10, 23, 15, 142, 537, "10:23:15.142537", "\047\193\169\143\100\066\226\064" ; 13, 29, 17, 213, 405, "13:29:17.213405", "\250\184\054\212\166\181\231\064" ; 15, 17, 21, 813, 605, "15:17:21.813605", "\092\090\013\009\058\224\234\064" ; 3, 43, 32, 893, 935, "03:43:32.893935", "\224\074\118\108\114\050\202\064" ; 11, 58, 24, 899, 365, "11:58:24.899365", "\197\027\153\199\028\012\229\064" ; 8, 9, 31, 197, 750, "08:09:31.197750", "\178\157\239\167\204\174\220\064" ; 16, 18, 27, 285, 710, "16:18:27.285710", "\069\076\137\036\105\170\236\064" ; 8, 50, 38, 212, 308, "08:50:38.212308", "\043\075\116\150\141\023\223\064" ; 20, 30, 58, 956, 681, "20:30:58.956681", "\124\188\144\078\047\008\242\064" ; 9, 19, 38, 88, 902, "09:19:38.088902", "\210\001\073\216\066\101\224\064" ; 11, 58, 58, 184, 791, "11:58:58.184791", "\179\208\206\233\069\016\229\064" ; 18, 22, 55, 358, 839, "18:22:55.358839", "\152\246\205\189\245\039\240\064" ; 18, 49, 7, 555, 18, "18:49:07.555018", "\235\141\090\225\056\138\240\064" ; 1, 5, 20, 373, 308, "01:05:20.373308", "\172\230\057\034\191\160\174\064" ; 18, 52, 44, 882, 246, "18:52:44.882246", "\080\251\173\029\206\151\240\064" ; 19, 36, 3, 504, 217, "19:36:03.504217", "\081\216\069\017\056\058\241\064" ; 19, 38, 19, 862, 212, "19:38:19.862212", "\099\207\158\203\189\066\241\064" ; 15, 11, 7, 769, 167, "15:11:07.769167", "\197\028\004\157\120\177\234\064" ; 9, 49, 31, 51, 365, "09:49:31.051365", "\101\054\200\164\097\069\225\064" ; 17, 31, 18, 530, 832, "17:31:18.530832", "\245\099\147\252\208\204\238\064" ; 3, 30, 18, 826, 583, "03:30:18.826583", "\054\196\120\205\105\165\200\064" ; 7, 51, 50, 551, 299, "07:51:50.551299", "\212\153\123\072\163\165\219\064" ; 16, 26, 13, 998, 896, "16:26:13.998896", "\131\190\244\246\191\228\236\064" ; 6, 14, 22, 620, 481, "06:14:22.620481", "\178\240\245\181\167\239\213\064" ; 10, 22, 46, 292, 462, "10:22:46.292462", "\171\068\217\091\201\062\226\064" ; 20, 51, 41, 531, 976, "20:51:41.531976", "\036\068\249\130\216\085\242\064" ; 17, 50, 42, 903, 262, "17:50:42.903262", "\183\181\133\231\092\094\239\064" ; 2, 51, 16, 4, 734, "02:51:16.004734", "\151\171\031\155\000\018\196\064" ; 13, 24, 47, 700, 67, "13:24:47.700067", "\192\232\242\102\246\147\231\064" ; 23, 56, 32, 977, 599, "23:56:32.977599", "\090\217\062\164\015\011\245\064" ; 15, 44, 34, 94, 748, "15:44:34.094748", "\043\245\044\008\067\172\235\064" ; 14, 34, 41, 347, 192, "14:34:41.347192", "\174\101\050\028\043\160\233\064" ; 11, 40, 21, 194, 360, "11:40:21.194360", "\117\118\050\056\166\132\228\064" ; 19, 36, 21, 343, 318, "19:36:21.343318", "\226\003\059\126\085\059\241\064" ; 12, 11, 35, 114, 964, "12:11:35.114964", "\135\251\200\173\227\110\229\064" ; 4, 4, 48, 584, 108, "04:04:48.584108", "\171\010\013\196\074\176\204\064" ; 1, 1, 37, 605, 684, "01:01:37.605684", "\108\151\054\028\054\227\172\064" ; 6, 28, 45, 631, 885, "06:28:45.631885", "\118\200\205\112\104\199\214\064" ; 16, 53, 58, 971, 347, "16:53:58.971347", "\194\077\070\021\223\180\237\064" ; 7, 54, 29, 118, 442, "07:54:29.118442", "\030\193\141\148\071\205\219\064" ; 2, 21, 31, 998, 456, "02:21:31.998456", "\063\253\103\205\255\149\192\064" ; 22, 49, 16, 516, 155, "22:49:16.516155", "\203\190\043\066\200\014\244\064" ; 2, 36, 21, 196, 57, "02:36:21.196057", "\147\081\101\024\153\082\194\064" ; 0, 4, 21, 216, 587, "00:04:21.216587", "\210\027\238\035\119\083\112\064" ; 22, 34, 26, 459, 216, "22:34:26.459216", "\093\224\242\088\039\215\243\064" ; 6, 6, 51, 482, 342, "06:06:51.482342", "\223\250\176\222\222\126\213\064" ; 4, 10, 22, 300, 345, "04:10:22.300345", "\066\120\180\113\038\087\205\064" ; 1, 15, 46, 743, 919, "01:15:46.743919", "\224\191\121\113\190\194\177\064" ; 0, 0, 41, 884, 256, "00:00:41.884256", "\089\165\244\076\047\241\068\064" ; 22, 48, 45, 623, 356, "22:48:45.623356", "\029\036\068\249\217\012\244\064" ; 19, 37, 12, 988, 127, "19:37:12.988127", "\213\065\094\207\143\062\241\064" ; 6, 40, 26, 24, 988, "06:40:26.024988", "\179\068\103\153\129\118\215\064" ; 5, 40, 9, 88, 628, "05:40:09.088628", "\097\198\020\172\069\238\211\064" ; 13, 27, 13, 605, 298, "13:27:13.605298", "\075\233\153\094\051\166\231\064" ; 6, 56, 52, 359, 756, "06:56:52.359756", "\163\007\062\006\023\109\216\064" ; 16, 17, 46, 207, 57, "16:17:46.207057", "\109\000\054\160\070\165\236\064" ; 18, 42, 14, 365, 918, "18:42:14.365918", "\049\213\204\218\101\112\240\064" ; 2, 46, 54, 55, 697, "02:46:54.055697", "\190\076\020\033\007\143\195\064" ; 20, 51, 15, 227, 949, "20:51:15.227949", "\194\217\173\165\051\084\242\064" ; 11, 39, 14, 591, 899, "11:39:14.591899", "\241\043\214\240\082\124\228\064" ; 18, 24, 6, 950, 870, "18:24:06.950870", "\012\118\195\054\111\044\240\064" ; 23, 7, 26, 396, 697, "23:07:26.396697", "\022\244\222\088\230\082\244\064" ; 6, 34, 55, 256, 795, "06:34:55.256795", "\178\075\084\111\208\035\215\064" ; 7, 55, 50, 984, 588, "07:55:50.984588", "\002\099\125\003\191\225\219\064" ; 22, 49, 17, 331, 714, "22:49:17.331714", "\218\086\179\078\213\014\244\064" ; 8, 22, 42, 631, 959, "08:22:42.631959", "\091\041\004\114\168\116\221\064" ; 14, 21, 9, 514, 796, "14:21:09.514796", "\004\118\053\121\176\058\233\064" ; 11, 45, 44, 495, 332, "11:45:44.495332", "\150\126\194\217\015\173\228\064" ; 2, 18, 5, 800, 911, "02:18:05.800911", "\000\108\064\132\230\046\192\064" ; 23, 1, 53, 401, 965, "23:01:53.401965", "\018\218\114\110\022\062\244\064" ; 22, 50, 18, 354, 58, "22:50:18.354058", "\175\184\056\170\165\018\244\064" ; 17, 41, 41, 539, 174, "17:41:41.539174", "\027\213\233\064\177\026\239\064" ; 10, 35, 50, 783, 967, "10:35:50.783967", "\069\246\065\022\217\160\226\064" ; 1, 31, 55, 365, 684, "01:31:55.365684", "\171\116\119\157\093\139\181\064" ; 12, 16, 51, 314, 711, "12:16:51.314711", "\150\205\028\018\106\150\229\064" ; 22, 34, 55, 545, 373, "22:34:55.545373", "\242\009\217\185\248\216\243\064" ; 12, 5, 3, 210, 950, "12:05:03.210950", "\227\054\026\192\230\061\229\064" ; 8, 31, 1, 0, 990, "08:31:01.000990", "\104\092\056\016\064\241\221\064" ; 7, 1, 49, 428, 649, "07:01:49.428649", "\030\055\252\110\091\183\216\064" ; 13, 12, 22, 510, 739, "13:12:22.510739", "\186\080\249\087\208\054\231\064" ; 21, 54, 2, 817, 404, "21:54:02.817404", "\122\055\022\020\173\063\243\064" ; 9, 19, 54, 855, 761, "09:19:54.855761", "\135\228\100\098\091\103\224\064" ; 22, 5, 58, 291, 160, "22:05:58.291160", "\094\099\151\168\100\108\243\064" ; 18, 43, 32, 990, 720, "18:43:32.990720", "\248\054\253\217\079\117\240\064" ; 10, 22, 58, 992, 916, "10:22:58.992916", "\117\198\247\197\095\064\226\064" ; 17, 58, 24, 489, 668, "17:58:24.489668", "\189\057\092\171\015\152\239\064" ; 14, 23, 22, 738, 574, "14:23:22.738574", "\245\240\101\162\087\075\233\064" ; 7, 2, 18, 58, 907, "07:02:18.058907", "\161\221\033\197\131\190\216\064" ; 19, 17, 23, 202, 824, "19:17:23.202824", "\238\096\196\062\051\244\240\064" ; 19, 13, 21, 816, 899, "19:13:21.816899", "\147\175\004\018\029\229\240\064" ; 6, 35, 10, 258, 619, "06:35:10.258619", "\200\180\054\141\144\039\215\064" ; 9, 20, 27, 510, 844, "09:20:27.510844", "\044\132\213\088\112\107\224\064" ; 8, 46, 33, 218, 734, "08:46:33.218734", "\034\228\188\255\077\218\222\064" ; 10, 23, 49, 94, 350, "10:23:49.094350", "\140\074\234\004\163\070\226\064" ; 16, 48, 34, 258, 47, "16:48:34.258047", "\059\200\235\065\072\140\237\064" ; 19, 55, 48, 745, 598, "19:55:48.745598", "\031\043\248\237\075\132\241\064" ; 8, 39, 7, 664, 907, "08:39:07.664907", "\249\022\214\141\234\106\222\064" ; 11, 24, 35, 811, 105, "11:24:35.811105", "\020\121\146\244\121\014\228\064" ; 21, 44, 4, 254, 471, "21:44:04.254471", "\237\046\080\018\068\026\243\064" ; 11, 47, 29, 417, 37, "11:47:29.417037", "\135\250\093\088\045\186\228\064" ; 8, 33, 11, 637, 409, "08:33:11.637409", "\075\030\079\203\232\017\222\064" ; 6, 32, 40, 540, 864, "06:32:40.540864", "\230\009\132\157\034\002\215\064" ; 20, 38, 6, 327, 177, "20:38:06.327177", "\048\243\029\060\229\034\242\064" ; 1, 53, 58, 953, 83, "01:53:58.953083", "\096\091\063\253\243\182\186\064" ; 13, 5, 10, 204, 772, "13:05:10.204772", "\100\002\126\141\198\000\231\064" ; 14, 23, 25, 250, 606, "14:23:25.250606", "\198\223\246\004\168\075\233\064" ; 19, 36, 44, 191, 582, "19:36:44.191582", "\136\073\184\016\195\060\241\064" ; 19, 32, 45, 318, 610, "19:32:45.318610", "\163\204\006\025\213\045\241\064" ; 23, 5, 0, 47, 815, "23:05:00.047815", "\085\169\217\195\192\073\244\064" ; 10, 8, 58, 959, 859, "10:08:58.959859", "\185\056\042\183\094\215\225\064" ; 9, 34, 21, 713, 132, "09:34:21.713132", "\056\051\250\209\182\211\224\064" ; 18, 10, 33, 207, 911, "18:10:33.207911", "\048\248\052\167\038\243\239\064" ; 14, 16, 37, 247, 134, "14:16:37.247134", "\248\143\133\232\167\024\233\064" ; 20, 13, 50, 228, 732, "20:13:50.228732", "\185\226\226\168\227\199\241\064" ; 1, 1, 38, 994, 77, "01:01:38.994077", "\106\025\169\247\252\229\172\064" ; 11, 2, 55, 229, 785, "11:02:55.229785", "\131\018\102\090\231\107\227\064" ; 15, 26, 18, 119, 955, "15:26:18.119955", "\064\222\171\214\067\035\235\064" ; 18, 6, 7, 659, 229, "18:06:07.659229", "\114\106\103\024\245\209\239\064" ; 20, 29, 52, 607, 947, "20:29:52.607947", "\043\162\038\186\009\004\242\064" ; 14, 39, 52, 103, 53, "14:39:52.103053", "\025\206\053\076\003\199\233\064" ; 13, 38, 12, 610, 448, "13:38:12.610448", "\125\062\202\136\147\248\231\064" ; 19, 4, 47, 265, 354, "19:04:47.265354", "\254\213\227\062\244\196\240\064" ; 0, 6, 30, 684, 448, "00:06:30.684448", "\001\253\190\127\243\106\120\064" ; 18, 43, 34, 734, 745, "18:43:34.734745", "\030\249\131\193\107\117\240\064" ; 18, 54, 47, 258, 589, "18:54:47.258589", "\034\056\046\035\116\159\240\064" ; 3, 32, 17, 956, 897, "03:32:17.956897", "\082\212\153\123\250\224\200\064" ; 2, 50, 52, 252, 299, "02:50:52.252299", "\232\104\085\075\032\006\196\064" ; 6, 10, 35, 899, 279, "06:10:35.899279", "\191\129\201\141\249\182\213\064" ; 0, 42, 15, 590, 741, "00:42:15.590741", "\208\182\154\117\046\207\163\064" ; 23, 57, 33, 578, 387, "23:57:33.578387", "\022\186\018\065\217\014\245\064" ; 23, 33, 42, 317, 170, "23:33:42.317170", "\148\217\032\019\101\181\244\064" ; 23, 12, 48, 0, 921, "23:12:48.000921", "\014\189\197\003\000\103\244\064" ; 2, 22, 44, 815, 853, "02:22:44.815853", "\172\000\223\109\104\186\192\064" ; 3, 57, 33, 621, 219, "03:57:33.621219", "\083\172\026\132\207\214\203\064" ; 5, 35, 46, 217, 752, "05:35:46.217752", "\169\021\166\239\141\172\211\064" ; 13, 12, 5, 601, 531, "13:12:05.601531", "\145\240\189\063\179\052\231\064" ; 0, 1, 53, 9, 325, "00:01:53.009325", "\065\130\226\199\152\064\092\064" ; 16, 45, 5, 528, 146, "16:45:05.528146", "\176\112\146\230\048\114\237\064" ; 18, 41, 14, 992, 110, "18:41:14.992110", "\064\188\174\223\175\108\240\064" ; 17, 30, 55, 557, 661, "17:30:55.557661", "\168\225\091\216\241\201\238\064" ; 10, 39, 30, 143, 168, "10:39:30.143168", "\186\014\213\148\068\188\226\064" ; 21, 47, 40, 344, 114, "21:47:40.344114", "\129\174\125\129\197\039\243\064" ; 9, 12, 30, 39, 196, "09:12:30.039196", "\068\248\023\065\193\047\224\064" ; 18, 29, 26, 595, 571, "18:29:26.595571", "\247\116\117\135\105\064\240\064" ; 3, 22, 43, 406, 897, "03:22:43.406897", "\236\109\051\021\180\193\199\064" ; 9, 22, 25, 668, 33, "09:22:25.668033", "\244\189\134\096\053\122\224\064" ; 2, 29, 4, 900, 969, "02:29:04.900969", "\219\194\243\082\115\120\193\064" ; 11, 51, 47, 812, 587, "11:51:47.812587", "\197\115\182\000\122\218\228\064" ; 0, 22, 16, 957, 248, "00:22:16.957248", "\166\216\209\056\212\227\148\064" ; 8, 0, 34, 404, 911, "08:00:34.404911", "\178\211\015\234\153\040\220\064" ; 20, 40, 7, 719, 879, "20:40:07.719879", "\161\215\159\132\123\042\242\064" ; 3, 23, 55, 175, 689, "03:23:55.175689", "\162\038\250\124\150\229\199\064" ; 0, 28, 30, 971, 135, "00:28:30.971135", "\001\164\054\113\226\187\154\064" ; 15, 23, 57, 85, 857, "15:23:57.085857", "\228\045\087\191\162\017\235\064" ; 20, 42, 47, 419, 904, "20:42:47.419904", "\183\065\237\183\118\052\242\064" ; 17, 12, 13, 526, 950, "17:12:13.526950", "\020\063\198\220\176\061\238\064" ; 19, 4, 34, 422, 71, "19:04:34.422071", "\090\133\205\192\038\196\240\064" ; 23, 15, 48, 458, 723, "23:15:48.458723", "\175\237\237\086\071\114\244\064" ; 2, 40, 19, 459, 875, "02:40:19.459875", "\160\026\047\221\186\201\194\064" ; 6, 12, 59, 289, 701, "06:12:59.289701", "\040\016\118\138\210\218\213\064" ; 2, 47, 49, 107, 748, "02:47:49.107748", "\027\188\175\202\141\170\195\064" ; 0, 32, 30, 402, 731, "00:32:30.402731", "\088\232\131\101\156\121\158\064" ; 3, 15, 53, 367, 581, "03:15:53.367581", "\209\234\228\012\175\244\198\064" ; 14, 22, 0, 469, 209, "14:22:00.469209", "\191\151\194\003\015\065\233\064" ; 13, 8, 54, 678, 8, "13:08:54.678008", "\078\213\061\178\213\028\231\064" ; 13, 57, 32, 781, 415, "13:57:32.781415", "\180\007\090\001\153\137\232\064" ; 10, 56, 41, 630, 419, "10:56:41.630419", "\121\119\100\044\052\061\227\064" ; 14, 56, 27, 254, 185, "14:56:27.254185", "\196\148\072\034\104\067\234\064" ; 7, 2, 6, 584, 220, "07:02:06.584220", "\107\072\220\099\165\187\216\064" ; 15, 49, 50, 862, 774, "15:49:50.862774", "\059\056\216\155\219\211\235\064" ; 8, 37, 47, 971, 106, "08:37:47.971106", "\189\199\153\038\254\086\222\064" ; 4, 51, 48, 316, 235, "04:51:48.316235", "\182\185\049\061\020\025\209\064" ; 17, 3, 23, 404, 721, "17:03:23.404721", "\096\116\121\243\108\251\237\064" ; 20, 49, 14, 483, 346, "20:49:14.483346", "\234\003\201\187\167\076\242\064" ; 1, 8, 41, 110, 360, "01:08:41.110360", "\201\142\141\064\028\025\176\064" ; 18, 45, 57, 803, 744, "18:45:57.803744", "\038\171\034\220\092\126\240\064" ; 13, 6, 29, 223, 63, "13:06:29.223063", "\062\004\085\035\167\010\231\064" ; 7, 35, 29, 805, 696, "07:35:29.805696", "\161\244\133\144\115\176\218\064" ; 10, 19, 43, 298, 133, "10:19:43.298133", "\156\055\078\138\233\039\226\064" ; 16, 1, 7, 379, 490, "16:01:07.379490", "\101\054\200\036\108\040\236\064" ; 13, 50, 49, 282, 938, "13:50:49.282938", "\025\254\211\013\041\087\232\064" ; 19, 14, 41, 996, 476, "19:14:41.996476", "\116\209\144\241\031\234\240\064" ; 15, 14, 8, 212, 720, "15:14:08.212720", "\102\044\154\206\006\200\234\064" ; 13, 22, 1, 129, 828, "13:22:01.129828", "\195\012\141\039\036\127\231\064" ; 8, 43, 57, 57, 481, "08:43:57.057481", "\201\201\196\173\067\179\222\064" ; 0, 45, 9, 911, 924, "00:45:09.911924", "\224\216\179\231\210\043\165\064" ; 11, 4, 20, 825, 540, "11:04:20.825540", "\177\220\210\106\154\118\227\064" ; 21, 21, 57, 264, 377, "21:21:57.264377", "\141\096\227\058\084\199\242\064" ; 18, 6, 0, 872, 831, "18:06:00.872831", "\254\070\059\238\027\209\239\064" ; 15, 26, 24, 0, 410, "15:26:24.000410", "\019\213\091\003\000\036\235\064" ; 1, 6, 55, 999, 698, "01:06:55.999698", "\192\143\106\216\255\095\175\064" ; 8, 41, 28, 953, 136, "08:41:28.953136", "\041\035\046\000\061\142\222\064" ; 16, 11, 40, 104, 949, "16:11:40.104949", "\088\001\190\091\131\119\236\064" ; 1, 49, 24, 976, 717, "01:49:24.976717", "\114\020\032\010\250\164\185\064" ; 16, 40, 55, 219, 156, "16:40:55.219156", "\151\113\083\003\231\082\237\064" ; 13, 38, 27, 899, 275, "13:38:27.899275", "\099\093\220\198\124\250\231\064" ; 4, 53, 46, 468, 866, "04:53:46.468866", "\013\138\230\001\158\054\209\064" ; 4, 19, 57, 569, 696, "04:19:57.569696", "\084\108\204\235\200\118\206\064" ; 16, 17, 32, 849, 83, "16:17:32.849083", "\147\028\176\043\155\163\236\064" ; 14, 26, 15, 352, 248, "14:26:15.352248", "\002\153\157\069\235\096\233\064" ; 17, 29, 4, 952, 932, "17:29:04.952932", "\234\063\107\126\030\188\238\064" ; 11, 9, 50, 431, 442, "11:09:50.431442", "\003\116\095\206\205\159\227\064" ; 14, 16, 16, 382, 537, "14:16:16.382537", "\016\060\190\061\012\022\233\064" ; 23, 19, 54, 90, 825, "23:19:54.090825", "\074\234\004\116\161\129\244\064" ; 21, 10, 23, 95, 753, "21:10:23.095753", "\056\076\052\136\241\155\242\064" ; 14, 6, 21, 7, 691, "14:06:21.007691", "\047\050\001\063\160\203\232\064" ; 7, 56, 20, 415, 981, "07:56:20.415981", "\177\197\110\159\026\233\219\064" ; 13, 43, 16, 926, 38, "13:43:16.926038", "\155\113\026\162\157\030\232\064" ; 1, 37, 44, 850, 307, "01:37:44.850307", "\144\052\184\173\217\232\182\064" ; 4, 59, 51, 285, 998, "04:59:51.285998", "\046\142\202\077\210\145\209\064" ; 9, 16, 17, 893, 834, "09:16:17.893834", "\193\194\073\154\060\076\224\064" ; 6, 47, 31, 192, 302, "06:47:31.192302", "\061\012\173\078\204\224\215\064" ; 22, 57, 18, 892, 356, "22:57:18.892356", "\199\021\023\071\238\044\244\064" ; 3, 54, 59, 719, 577, "03:54:59.719577", "\250\096\025\027\220\137\203\064" ; 4, 24, 23, 492, 155, "04:24:23.492155", "\200\094\239\254\190\251\206\064" ; 5, 37, 43, 317, 902, "05:37:43.317902", "\085\161\129\088\212\201\211\064" ; 23, 0, 20, 885, 730, "23:00:20.885730", "\113\056\243\043\078\056\244\064" ; 0, 57, 23, 241, 120, "00:57:23.241120", "\211\164\020\116\123\230\170\064" ; 23, 3, 22, 415, 869, "23:03:22.415869", "\166\064\102\167\166\067\244\064" ; 5, 8, 10, 929, 30, "05:08:10.929030", "\192\062\058\117\187\014\210\064" ; 20, 40, 40, 349, 269, "20:40:40.349269", "\072\023\155\150\133\044\242\064" ; 0, 32, 41, 877, 148, "00:32:41.877148", "\002\215\021\051\130\167\158\064" ; 9, 36, 42, 676, 913, "09:36:42.676913", "\168\115\069\169\085\229\224\064" ; 6, 32, 50, 495, 806, "06:32:50.495806", "\202\022\073\187\159\004\215\064" ; 20, 26, 28, 704, 305, "20:26:28.704305", "\214\081\213\068\075\247\241\064" ; 3, 36, 13, 958, 473, "03:36:13.958473", "\141\070\062\175\250\086\201\064" ; 13, 36, 31, 3, 865, "13:36:31.003865", "\019\126\169\031\224\235\231\064" ; 5, 56, 22, 954, 407, "05:56:22.954407", "\005\025\001\021\189\225\212\064" ; 12, 44, 53, 658, 696, "12:44:53.658696", "\065\162\009\020\181\104\230\064" ; 21, 39, 15, 311, 287, "21:39:15.311287", "\203\019\008\251\052\008\243\064" ; 16, 46, 18, 878, 709, "16:46:18.878709", "\054\086\098\030\092\123\237\064" ; 10, 51, 30, 851, 635, "10:51:30.851635", "\036\011\152\064\091\022\227\064" ; 19, 37, 16, 186, 249, "19:37:16.186249", "\063\059\224\250\194\062\241\064" ; 15, 39, 0, 414, 566, "15:39:00.414566", "\129\234\031\068\141\130\235\064" ; 16, 45, 9, 222, 594, "16:45:09.222594", "\201\115\125\031\167\114\237\064" ; 21, 49, 36, 442, 15, "21:49:36.442015", "\021\082\126\018\007\047\243\064" ; 16, 0, 41, 78, 938, "16:00:41.078938", "\013\252\168\134\034\037\236\064" ; 16, 43, 16, 925, 103, "16:43:16.925103", "\078\155\113\154\157\100\237\064" ; 1, 48, 32, 968, 956, "01:48:32.968956", "\067\027\128\013\248\112\185\064" ; 22, 53, 9, 692, 588, "22:53:09.692588", "\153\039\215\020\091\029\244\064" ; 1, 33, 34, 352, 761, "01:33:34.352761", "\078\126\139\078\090\238\181\064" ; 0, 21, 14, 463, 777, "00:21:14.463777", "\140\158\091\232\218\233\147\064" ; 3, 13, 34, 168, 328, "03:13:34.168328", "\128\155\197\139\021\175\198\064" ; 1, 39, 51, 752, 202, "01:39:51.752202", "\253\109\079\144\192\103\183\064" ; 4, 28, 59, 439, 365, "04:28:59.439365", "\001\193\028\061\184\133\207\064" ; 5, 26, 37, 410, 566, "05:26:37.410566", "\182\157\182\070\090\035\211\064" ; 15, 20, 10, 732, 987, "15:20:10.732987", "\045\039\161\116\087\245\234\064" ; 4, 24, 47, 974, 220, "04:24:47.974220", "\142\175\061\179\252\007\207\064" ; 13, 50, 24, 657, 72, "13:50:24.657072", "\228\219\187\006\021\084\232\064" ; 13, 3, 56, 628, 633, "13:03:56.628633", "\006\244\194\029\148\247\230\064" ; 12, 5, 46, 719, 104, "12:05:46.719104", "\077\100\230\002\087\067\229\064" ; 0, 28, 58, 930, 119, "00:28:58.930119", "\142\121\029\113\184\043\155\064" ; 2, 6, 2, 356, 573, "02:06:02.356573", "\163\061\094\072\091\138\189\064" ; 0, 8, 34, 528, 941, "00:08:34.528941", "\028\068\107\069\059\020\128\064" ; 18, 13, 45, 367, 549, "18:13:45.367549", "\107\015\123\225\149\005\240\064" ; 20, 43, 41, 98, 620, "20:43:41.098620", "\172\144\242\147\209\055\242\064" ; 17, 20, 37, 219, 878, "17:20:37.219878", "\099\150\061\009\167\124\238\064" ; 6, 21, 42, 695, 650, "06:21:42.695650", "\222\147\135\133\172\093\214\064" ; 8, 36, 42, 202, 72, "08:36:42.202072", "\220\101\191\238\140\070\222\064" ; 16, 54, 14, 606, 453, "16:54:14.606453", "\050\031\016\104\211\182\237\064" ; 2, 20, 34, 541, 99, "02:20:34.541099", "\115\102\187\066\069\121\192\064" ; 22, 27, 27, 668, 336, "22:27:27.668336", "\236\022\129\177\250\188\243\064" ; 7, 12, 55, 659, 13, "07:12:55.659013", "\169\220\068\045\234\093\217\064" ; 23, 19, 7, 937, 671, "23:19:07.937671", "\119\078\179\000\191\126\244\064" ; 5, 53, 11, 301, 100, "05:53:11.301100", "\053\239\056\069\211\177\212\064" ; 22, 38, 5, 457, 692, "22:38:05.457692", "\186\216\180\082\215\228\243\064" ; 13, 26, 30, 257, 790, "13:26:30.257790", "\103\208\208\063\200\160\231\064" ; 17, 7, 46, 525, 449, "17:07:46.525449", "\215\107\122\208\080\028\238\064" ; 10, 6, 9, 586, 632, "10:06:09.586632", "\218\120\176\197\050\194\225\064" ; 3, 9, 39, 484, 127, "03:09:39.484127", "\014\160\223\247\189\057\198\064" ; 9, 57, 29, 508, 528, "09:57:29.508528", "\035\131\220\069\048\129\225\064" ; 6, 27, 5, 803, 766, "06:27:05.803766", "\233\242\230\112\115\174\214\064" ; 13, 25, 33, 19, 423, "13:25:33.019423", "\185\251\028\159\160\153\231\064" ; 19, 0, 1, 325, 200, "19:00:01.325200", "\074\234\004\052\021\179\240\064" ; 22, 52, 46, 830, 982, "22:52:46.830982", "\025\200\179\075\237\027\244\064" ; 14, 5, 38, 22, 961, "14:05:38.022961", "\002\181\024\188\064\198\232\064" ; 9, 6, 27, 137, 865, "09:06:27.137865", "\073\220\099\105\100\002\224\064" ; 4, 36, 46, 688, 171, "04:36:46.688171", "\195\096\254\010\172\055\208\064" ; 8, 47, 49, 630, 463, "08:47:49.630463", "\150\123\129\089\104\237\222\064" ; 6, 24, 6, 382, 19, "06:24:06.382019", "\221\209\255\114\152\129\214\064" ; 0, 19, 23, 774, 771, "00:19:23.774771", "\142\171\145\093\025\047\146\064" ; 2, 20, 27, 961, 311, "02:20:27.961311", "\036\037\061\012\251\117\192\064" ; 8, 21, 49, 484, 488, "08:21:49.484488", "\212\244\217\001\095\103\221\064" ; 22, 10, 25, 408, 784, "22:10:25.408784", "\114\023\097\138\022\125\243\064" ; 9, 40, 50, 597, 582, "09:40:50.597582", "\086\073\100\031\083\004\225\064" ; 18, 59, 32, 691, 227, "18:59:32.691227", "\242\010\068\015\075\177\240\064" ; 19, 22, 37, 779, 432, "19:22:37.779432", "\087\176\141\120\220\007\241\064" ; 5, 44, 31, 688, 969, "05:44:31.688969", "\189\110\017\024\236\047\212\064" ; 16, 30, 58, 728, 66, "16:30:58.728066", "\107\017\081\076\087\008\237\064" ; 2, 5, 35, 907, 463, "02:05:35.907463", "\085\195\126\079\232\111\189\064" ; 10, 39, 17, 238, 457, "10:39:17.238457", "\016\147\112\161\167\186\226\064" ; 10, 4, 44, 258, 739, "10:04:44.258739", "\231\002\151\071\136\183\225\064" ; 22, 15, 14, 130, 519, "22:15:14.130519", "\072\023\155\022\034\143\243\064" ; 23, 49, 55, 347, 841, "23:49:55.347841", "\115\185\193\144\053\242\244\064" ; 0, 24, 17, 954, 941, "00:24:17.954941", "\112\178\013\220\209\199\150\064" ; 6, 40, 34, 332, 409, "06:40:34.332409", "\249\101\048\070\149\120\215\064" ; 8, 24, 33, 938, 497, "08:24:33.938497", "\153\184\085\016\124\144\221\064" ; 18, 55, 21, 237, 129, "18:55:21.237129", "\062\199\071\203\147\161\240\064" ; 17, 43, 44, 755, 845, "17:43:44.755845", "\123\218\225\047\024\042\239\064" ; 13, 37, 52, 410, 939, "13:37:52.410939", "\181\139\105\038\013\246\231\064" ; 20, 31, 56, 89, 40, "20:31:56.089040", "\001\053\181\108\193\011\242\064" ; 2, 14, 59, 928, 819, "02:14:59.928819", "\231\252\020\199\237\163\191\064" ; 8, 16, 11, 138, 629, "08:16:11.138629", "\081\043\076\223\200\018\221\064" ; 18, 11, 0, 207, 217, "18:11:00.207217", "\198\139\133\161\134\246\239\064" ; 9, 57, 54, 856, 907, "09:57:54.856907", "\151\058\200\107\091\132\225\064" ; 18, 42, 27, 322, 811, "18:42:27.322811", "\253\221\059\042\053\113\240\064" ; 2, 58, 3, 469, 886, "02:58:03.469886", "\108\117\057\037\188\221\196\064" ; 4, 47, 46, 937, 629, "04:47:46.937629", "\178\016\029\002\188\220\208\064" ; 6, 6, 13, 276, 302, "06:06:13.276302", "\117\149\238\174\081\117\213\064" ; 16, 59, 26, 845, 699, "16:59:26.845699", "\104\089\247\015\219\221\237\064" ; 23, 19, 36, 37, 917, "23:19:36.037917", "\047\219\078\155\128\128\244\064" ; 9, 1, 21, 910, 745, "09:01:21.910745", "\128\101\165\073\122\184\223\064" ; 6, 43, 17, 578, 715, "06:43:17.578715", "\173\163\170\009\101\161\215\064" ; 13, 37, 40, 609, 317, "13:37:40.609317", "\124\093\134\127\147\244\231\064" ; 16, 9, 32, 692, 812, "16:09:32.692812", "\073\018\132\043\150\103\236\064" ; 8, 58, 52, 235, 128, "08:58:52.235128", "\152\079\086\012\015\147\223\064" ; 16, 17, 45, 444, 365, "16:17:45.444365", "\208\242\060\056\046\165\236\064" ; 21, 39, 39, 990, 594, "21:39:39.990594", "\026\024\121\217\191\009\243\064" ; 0, 7, 28, 450, 678, "00:07:28.450678", "\109\112\034\250\053\007\124\064" ; 13, 35, 30, 615, 852, "13:35:30.615852", "\229\064\015\181\083\228\231\064" ; 12, 9, 54, 207, 420, "12:09:54.207420", "\145\068\047\163\070\098\229\064" ; 17, 30, 45, 225, 646, "17:30:45.225646", "\207\245\125\056\167\200\238\064" ; 14, 1, 13, 282, 635, "14:01:13.282635", "\054\142\088\011\041\165\232\064" ; 3, 8, 19, 657, 985, "03:08:19.657985", "\033\060\218\056\212\017\198\064" ; 11, 25, 47, 235, 579, "11:25:47.235579", "\148\248\220\137\103\023\228\064" ; 11, 45, 9, 71, 311, "11:45:09.071311", "\156\001\046\072\162\168\228\064" ; 23, 49, 41, 201, 524, "23:49:41.201524", "\214\058\113\057\083\241\244\064" ; 23, 23, 55, 234, 749, "23:23:55.234749", "\220\042\136\193\179\144\244\064" ; 0, 22, 31, 108, 278, "00:22:31.108278", "\129\147\109\224\110\028\149\064" ; 6, 45, 2, 4, 8, "06:45:02.004008", "\059\197\170\065\128\187\215\064" ; 16, 35, 16, 626, 8, "16:35:16.626008", "\225\237\065\008\148\040\237\064" ; 15, 57, 4, 522, 184, "15:57:04.522184", "\079\056\187\181\016\010\236\064" ; 11, 19, 55, 375, 13, "11:19:55.375013", "\082\067\027\000\108\235\227\064" ; 11, 33, 55, 600, 94, "11:33:55.600094", "\017\085\248\051\115\084\228\064" ; 7, 13, 1, 388, 141, "07:13:01.388141", "\079\089\077\215\088\095\217\064" ; 0, 19, 44, 313, 671, "00:19:44.313671", "\209\122\248\050\065\129\146\064" ; 5, 59, 54, 437, 271, "05:59:54.437271", "\032\129\063\252\155\022\213\064" ; 17, 56, 47, 185, 887, "17:56:47.185887", "\056\075\201\242\229\139\239\064" ; 10, 11, 22, 988, 674, "10:11:22.988674", "\013\168\055\163\095\233\225\064" ; 15, 25, 45, 821, 62, "15:25:45.821062", "\192\208\035\070\058\031\235\064" ; 6, 24, 39, 420, 235, "06:24:39.420235", "\104\087\033\229\218\137\214\064" ; 23, 45, 43, 776, 313, "23:45:43.776313", "\039\046\199\107\124\226\244\064" ; 8, 28, 55, 469, 701, "08:28:55.469701", "\122\200\148\015\222\209\221\064" ; 3, 44, 29, 467, 195, "03:44:29.467195", "\238\182\011\205\187\078\202\064" ; 18, 48, 25, 63, 236, "18:48:25.063236", "\127\192\003\003\145\135\240\064" ; 15, 3, 4, 441, 917, "15:03:04.441917", "\209\030\047\036\014\117\234\064" ; 11, 43, 32, 129, 242, "11:43:32.129242", "\105\030\192\034\132\156\228\064" ; 20, 58, 23, 441, 669, "20:58:23.441669", "\107\131\019\017\247\110\242\064" ; 7, 10, 23, 729, 252, "07:10:23.729252", "\163\148\016\172\238\055\217\064" ; 2, 40, 10, 755, 696, "02:40:10.755696", "\219\130\165\186\096\197\194\064" ; 7, 45, 2, 554, 948, "07:45:02.554948", "\191\157\068\132\163\063\219\064" ; 20, 47, 57, 362, 115, "20:47:57.362115", "\038\025\057\203\213\071\242\064" ; 16, 7, 51, 627, 894, "16:07:51.627894", "\107\040\181\023\244\090\236\064" ; 7, 59, 7, 864, 561, "07:59:07.864561", "\026\169\247\084\247\018\220\064" ; 3, 17, 50, 428, 447, "03:17:50.428447", "\137\238\089\215\054\047\199\064" ; 15, 22, 23, 772, 146, "15:22:23.772146", "\055\135\107\181\248\005\235\064" ; 22, 9, 55, 108, 964, "22:09:55.108964", "\007\009\081\190\049\123\243\064" ; 13, 24, 31, 946, 450, "13:24:31.946450", "\170\130\081\073\254\145\231\064" ; 10, 16, 4, 741, 752, "10:16:04.741752", "\184\176\110\188\151\012\226\064" ; 8, 0, 50, 53, 857, "08:00:50.053857", "\106\161\100\114\131\044\220\064" ; 3, 53, 42, 808, 610, "03:53:42.808610", "\156\080\136\128\103\099\203\064" ; 11, 54, 39, 365, 690, "11:54:39.365690", "\207\131\187\179\235\239\228\064" ; 21, 32, 16, 270, 978, "21:32:16.270978", "\255\006\237\085\004\238\242\064" ; 1, 38, 5, 811, 61, "01:38:05.811061", "\015\150\177\161\207\253\182\064" ; 18, 33, 50, 910, 11, "18:33:50.910011", "\192\177\103\143\238\080\240\064" ; 23, 19, 44, 155, 568, "23:19:44.155568", "\005\223\052\125\002\129\244\064" ; 18, 29, 4, 550, 947, "18:29:04.550947", "\045\205\173\208\008\063\240\064" ; 12, 32, 25, 863, 764, "12:32:25.863764", "\110\102\244\163\059\011\230\064" ; 6, 44, 32, 233, 833, "06:44:32.233833", "\238\175\030\247\014\180\215\064" ; 13, 25, 6, 564, 3, "13:25:06.564003", "\251\004\080\012\082\150\231\064" ; 18, 45, 0, 3, 587, "18:45:00.003587", "\251\061\177\014\192\122\240\064" ; 16, 17, 53, 252, 272, "16:17:53.252272", "\182\186\156\018\040\166\236\064" ; 12, 17, 58, 202, 84, "12:17:58.202084", "\097\221\120\119\198\158\229\064" ; 7, 14, 29, 387, 801, "07:14:29.387801", "\022\073\187\209\088\117\217\064" ; 15, 35, 0, 181, 442, "15:35:00.181442", "\003\116\095\206\133\100\235\064" ; 1, 42, 9, 97, 108, "01:42:09.097108", "\046\228\017\220\024\241\183\064" ; 17, 28, 8, 466, 481, "17:28:08.466481", "\231\143\105\237\014\181\238\064" ; 2, 2, 47, 632, 857, "02:02:47.632857", "\011\150\234\002\162\199\188\064" ; 22, 58, 40, 400, 50, "22:58:40.400050", "\044\212\154\102\006\050\244\064" ; 14, 15, 26, 273, 354, "14:15:26.273354", "\072\227\080\191\200\015\233\064" ; 16, 59, 46, 621, 636, "16:59:46.621636", "\064\046\113\228\083\224\237\064" ; 14, 42, 28, 621, 587, "14:42:28.621587", "\148\107\010\228\147\218\233\064" ; 6, 55, 36, 296, 314, "06:55:36.296314", "\214\254\206\246\018\090\216\064" ; 21, 37, 56, 174, 619, "21:37:56.174619", "\228\074\061\203\066\003\243\064" ; 2, 13, 17, 92, 606, "02:13:17.092606", "\105\221\006\181\023\061\191\064" ; 6, 16, 54, 671, 507, "06:16:54.671507", "\002\127\248\249\170\021\214\064" ; 13, 13, 47, 34, 180, "13:13:47.034180", "\198\167\000\024\097\065\231\064" ; 14, 1, 50, 987, 960, "14:01:50.987960", "\056\074\094\157\223\169\232\064" ; 1, 6, 50, 213, 289, "01:06:50.213289", "\050\063\055\052\109\084\175\064" ; 14, 2, 23, 204, 328, "14:02:23.204328", "\181\223\218\137\230\173\232\064" ; 10, 18, 50, 328, 8, "10:18:50.328008", "\027\162\010\127\074\033\226\064" ; 19, 27, 12, 757, 197, "19:27:12.757197", "\250\153\122\029\012\025\241\064" ; 0, 7, 58, 273, 264, "00:07:58.273264", "\202\114\018\074\095\228\125\064" ; 19, 47, 9, 513, 266, "19:47:09.513266", "\195\104\086\054\216\099\241\064" ; 8, 3, 23, 514, 945, "08:03:23.514945", "\143\223\219\244\224\082\220\064" ; 1, 14, 54, 382, 92, "01:14:54.382092", "\016\004\200\208\097\142\177\064" ; 5, 7, 55, 66, 879, "05:07:55.066879", "\114\219\190\071\196\010\210\064" ; 10, 59, 50, 607, 131, "10:59:50.607131", "\173\253\157\109\211\084\227\064" ; 8, 26, 9, 414, 959, "08:26:09.414959", "\140\049\176\142\090\168\221\064" ; 13, 50, 49, 166, 817, "13:50:49.166817", "\237\154\144\086\037\087\232\064" ; 14, 31, 9, 877, 263, "14:31:09.877263", "\224\218\137\018\188\133\233\064" ; 3, 28, 31, 941, 902, "03:28:31.941902", "\005\167\062\144\248\111\200\064" ; 6, 8, 11, 396, 655, "06:08:11.396655", "\051\167\203\098\217\146\213\064" ; 19, 4, 41, 342, 767, "19:04:41.342767", "\243\063\249\123\149\196\240\064" ; 14, 56, 8, 294, 844, "14:56:08.294844", "\046\175\092\111\009\065\234\064" ; 13, 55, 52, 500, 593, "13:55:52.500593", "\115\156\219\004\016\125\232\064" ; 5, 37, 21, 839, 394, "05:37:21.839394", "\157\156\161\184\117\196\211\064" ; 14, 35, 49, 680, 26, "14:35:49.680026", "\206\226\197\194\181\168\233\064" ; 9, 48, 26, 321, 662, "09:48:26.321662", "\076\027\014\075\074\061\225\064" ; 23, 13, 51, 389, 101, "23:13:51.389101", "\093\248\193\057\246\106\244\064" ; 7, 33, 52, 3, 2, "07:33:52.003002", "\245\076\047\049\000\152\218\064" ; 19, 9, 16, 943, 694, "19:09:16.943694", "\055\225\094\025\207\213\240\064" ; 0, 5, 31, 653, 303, "00:05:31.653303", "\015\182\216\237\115\186\116\064" ; 17, 26, 32, 212, 402, "17:26:32.212402", "\115\071\255\203\006\169\238\064" ; 3, 31, 25, 962, 226, "03:31:25.962226", "\174\184\056\042\251\198\200\064" ; 19, 6, 33, 513, 297, "19:06:33.513297", "\067\234\118\054\152\203\240\064" ; 10, 47, 52, 498, 627, "10:47:52.498627", "\061\156\192\244\015\251\226\064" ; 17, 37, 56, 763, 657, "17:37:56.763657", "\011\206\224\111\152\254\238\064" ; 0, 28, 32, 97, 385, "00:28:32.097385", "\124\184\228\184\099\192\154\064" ; 22, 37, 1, 673, 688, "22:37:01.673688", "\123\017\109\199\218\224\243\064" ; 21, 6, 49, 249, 881, "21:06:49.249881", "\046\056\131\255\147\142\242\064" ; 9, 21, 59, 806, 199, "09:21:59.806199", "\098\216\097\204\249\118\224\064" ; 0, 39, 53, 44, 105, "00:39:53.044105", "\046\057\238\148\022\178\162\064" ; 11, 46, 33, 491, 792, "11:46:33.491792", "\142\147\194\188\047\179\228\064" ; 9, 5, 0, 228, 204, "09:05:00.228204", "\052\243\228\154\014\239\223\064" ; 12, 41, 3, 606, 791, "12:41:03.606791", "\144\245\212\106\243\075\230\064" ; 10, 2, 29, 552, 364, "10:02:29.552364", "\112\068\247\172\177\166\225\064" ; 11, 54, 21, 16, 426, "11:54:21.016426", "\154\209\143\134\160\237\228\064" ; 0, 41, 18, 389, 119, "00:41:18.389119", "\129\006\155\058\199\092\163\064" ; 17, 13, 31, 626, 896, "17:13:31.626896", "\063\051\136\015\116\071\238\064" ; 7, 30, 50, 241, 617, "07:30:50.241617", "\075\038\167\118\143\106\218\064" ; 6, 12, 57, 775, 209, "06:12:57.775209", "\165\053\006\157\113\218\213\064" ; 4, 35, 43, 130, 378, "04:35:43.130378", "\136\247\028\088\200\039\208\064" ; 4, 47, 47, 905, 963, "04:47:47.905963", "\024\060\076\251\249\220\208\064" ; 23, 8, 29, 319, 898, "23:08:29.319898", "\129\093\077\030\213\086\244\064" ; 14, 16, 21, 613, 796, "14:16:21.613796", "\077\130\055\164\179\022\233\064" ; 21, 12, 34, 54, 665, "21:12:34.054665", "\052\104\232\223\032\164\242\064" ; 5, 42, 29, 783, 258, "05:42:29.783258", "\149\041\230\032\114\017\212\064" ; 17, 34, 20, 355, 388, "17:34:20.355388", "\173\167\086\095\139\227\238\064" ; 1, 8, 9, 782, 86, "01:08:09.782086", "\082\129\147\109\144\243\175\064" ; 2, 26, 52, 97, 375, "02:26:52.097375", "\057\180\200\118\012\054\193\064" ; 15, 9, 15, 732, 423, "15:09:15.732423", "\251\091\002\112\119\163\234\064" ; 10, 0, 22, 275, 640, "10:00:22.275640", "\047\250\010\210\200\150\225\064" ; 19, 57, 40, 649, 659, "19:57:40.649659", "\233\213\000\101\074\139\241\064" ; 23, 13, 56, 625, 267, "23:13:56.625267", "\068\248\023\001\074\107\244\064" ; 4, 8, 46, 291, 587, "04:08:46.291587", "\120\010\185\082\037\039\205\064" ; 15, 31, 47, 920, 710, "15:31:47.920710", "\099\209\116\118\125\076\235\064" ; 14, 18, 2, 108, 702, "14:18:02.108702", "\224\157\124\122\067\035\233\064" ; 13, 34, 23, 607, 356, "13:34:23.607356", "\161\217\117\111\243\219\231\064" ; 7, 31, 8, 987, 685, "07:31:08.987685", "\112\037\059\054\063\111\218\064" ; 11, 45, 50, 43, 597, "11:45:50.043597", "\038\137\037\101\193\173\228\064" ; 10, 31, 27, 261, 617, "10:31:27.261617", "\098\157\042\095\232\127\226\064" ; 20, 59, 0, 179, 663, "20:59:00.179663", "\085\079\230\223\066\113\242\064" ; 9, 38, 49, 562, 239, "09:38:49.562239", "\177\164\220\253\049\245\224\064" ; 3, 1, 34, 95, 942, "03:01:34.095942", "\040\212\211\071\012\071\197\064" ; 9, 59, 36, 425, 749, "09:59:36.425749", "\234\093\188\159\013\145\225\064" ; 22, 49, 1, 700, 631, "22:49:01.700631", "\249\217\200\053\219\013\244\064" ; 5, 19, 9, 327, 872, "05:19:09.327872", "\082\215\218\251\084\179\210\064" ; 2, 37, 35, 63, 388, "02:37:35.063388", "\123\021\025\029\136\119\194\064" ; 5, 12, 22, 944, 566, "05:12:22.944566", "\186\243\196\115\188\077\210\064" ; 4, 4, 28, 27, 677, "04:04:28.027677", "\237\128\235\138\003\166\204\064" ; 6, 32, 4, 495, 140, "06:32:04.495140", "\188\174\095\176\031\249\214\064" ; 13, 21, 23, 275, 570, "13:21:23.275570", "\056\045\120\209\104\122\231\064" ; 7, 47, 20, 929, 707, "07:47:20.929707", "\247\201\081\128\059\098\219\064" ; 7, 36, 43, 368, 7, "07:36:43.368007", "\108\059\109\141\215\194\218\064" ; 1, 53, 41, 325, 435, "01:53:41.325435", "\249\073\181\079\083\165\186\064" ; 13, 58, 39, 346, 697, "13:58:39.346697", "\148\078\036\024\235\145\232\064" ; 4, 56, 20, 386, 302, "04:56:20.386302", "\024\006\044\185\024\093\209\064" ; 15, 2, 10, 963, 506, "15:02:10.963506", "\240\136\010\213\094\110\234\064" ; 22, 49, 57, 497, 778, "22:49:57.497778", "\107\016\230\246\087\017\244\064" ; 2, 25, 53, 478, 376, "02:25:53.478376", "\152\189\108\059\189\024\193\064" ; 15, 8, 58, 318, 730, "15:08:58.318730", "\200\065\009\051\074\161\234\064" ; 8, 46, 17, 950, 548, "08:46:17.950548", "\082\071\199\213\124\214\222\064" ; 19, 18, 51, 149, 696, "19:18:51.149696", "\006\162\039\101\178\249\240\064" ; 9, 2, 28, 398, 630, "09:02:28.398630", "\077\103\039\131\025\201\223\064" ; 4, 9, 11, 996, 704, "04:09:11.996704", "\229\037\255\147\255\051\205\064" ; 3, 3, 2, 652, 665, "03:03:02.652665", "\031\215\134\138\083\115\197\064" ; 22, 54, 57, 499, 490, "22:54:57.499490", "\235\057\233\253\023\036\244\064" ; 9, 23, 9, 136, 107, "09:23:09.136107", "\056\017\253\090\164\127\224\064" ; 2, 16, 26, 54, 812, "02:16:26.054812", "\110\195\040\008\014\250\191\064" ; 12, 42, 57, 946, 953, "12:42:57.946953", "\188\096\112\077\062\090\230\064" ; 13, 5, 42, 796, 523, "13:05:42.796523", "\113\205\029\125\217\004\231\064" ; 12, 13, 22, 717, 460, "12:13:22.717460", "\134\172\110\245\086\124\229\064" ; 16, 12, 18, 295, 371, "16:12:18.295371", "\038\226\173\115\073\124\236\064" ; 6, 53, 22, 751, 912, "06:53:22.751912", "\094\130\083\031\176\056\216\064" ; 7, 44, 0, 750, 406, "07:44:00.750406", "\046\227\166\006\048\048\219\064" ; 5, 24, 26, 657, 962, "05:24:26.657962", "\000\166\012\028\170\002\211\064" ; 16, 32, 9, 76, 345, "16:32:09.076345", "\199\017\107\113\034\017\237\064" ; 4, 43, 16, 843, 441, "04:43:16.843441", "\199\245\239\250\053\153\208\064" ; 20, 1, 6, 153, 955, "20:01:06.153955", "\161\132\153\118\034\152\241\064" ; 8, 30, 8, 921, 646, "08:30:08.921646", "\031\129\063\252\058\228\221\064" ; 3, 11, 42, 792, 941, "03:11:42.792941", "\084\055\023\127\101\119\198\064" ; 8, 51, 2, 609, 400, "08:51:02.609400", "\140\219\104\000\167\029\223\064" ; 22, 47, 28, 106, 713, "22:47:28.106713", "\209\176\024\181\001\008\244\064" ; 2, 19, 28, 919, 894, "02:19:28.919894", "\229\042\022\191\117\088\192\064" ; 2, 52, 8, 383, 486, "02:52:08.383486", "\061\186\017\022\049\044\196\064" ; 2, 4, 13, 408, 602, "02:04:13.408602", "\021\003\036\154\104\029\189\064" ; 11, 21, 4, 270, 809, "11:21:04.270809", "\206\162\119\170\008\244\227\064" ; 20, 44, 37, 338, 539, "20:44:37.338539", "\215\222\167\106\085\059\242\064" ; 8, 52, 41, 364, 592, "08:52:41.364592", "\025\175\121\085\087\054\223\064" ; 1, 52, 27, 556, 514, "01:52:27.556514", "\196\149\179\119\142\091\186\064" ; 21, 2, 23, 849, 861, "21:02:23.849861", "\018\217\007\153\253\125\242\064" ; 5, 43, 6, 238, 384, "05:43:06.238384", "\249\246\174\065\143\026\212\064" ; 1, 5, 5, 173, 294, "01:05:05.173294", "\047\189\253\185\088\130\174\064" ; 22, 25, 40, 284, 604, "22:25:40.284604", "\133\236\188\141\068\182\243\064" ; 0, 33, 35, 970, 692, "00:33:35.970692", "\245\105\021\253\225\127\159\064" ; 6, 33, 45, 767, 784, "06:33:45.767784", "\153\128\095\035\113\018\215\064" ; 16, 33, 29, 412, 337, "16:33:29.412337", "\061\093\221\049\045\027\237\064" ; 18, 34, 56, 312, 986, "18:34:56.312986", "\162\155\253\001\005\085\240\064" ; 7, 47, 57, 477, 180, "07:47:57.477180", "\147\251\029\138\094\107\219\064" ; 4, 27, 24, 292, 632, "04:27:24.292632", "\225\034\247\116\037\086\207\064" ; 18, 25, 11, 951, 212, "18:25:11.951212", "\249\018\042\056\127\048\240\064" ; 23, 6, 11, 405, 216, "23:06:11.405216", "\189\197\195\123\054\078\244\064" ; 18, 52, 28, 186, 622, "18:52:28.186622", "\172\089\103\252\194\150\240\064" ; 10, 47, 4, 707, 248, "10:47:04.707248", "\197\142\198\161\022\245\226\064" ; 20, 34, 12, 905, 317, "20:34:12.905317", "\184\173\045\124\078\020\242\064" ; 8, 18, 50, 277, 320, "08:18:50.277320", "\161\098\156\191\145\058\221\064" ; 0, 2, 51, 185, 801, "00:02:51.185801", "\013\082\240\020\242\101\101\064" ; 22, 56, 20, 415, 639, "22:56:20.415639", "\127\020\117\166\070\041\244\064" ; 18, 13, 43, 609, 636, "18:13:43.609636", "\167\173\017\193\121\005\240\064" ; 7, 13, 52, 843, 109, "07:13:52.843109", "\126\115\127\245\053\108\217\064" ; 16, 19, 22, 608, 373, "16:19:22.608373", "\089\167\202\119\083\177\236\064" ; 4, 9, 11, 625, 885, "04:09:11.625885", "\007\235\255\028\208\051\205\064" ; 14, 46, 22, 643, 700, "14:46:22.643700", "\013\190\048\153\212\247\233\064" ; 12, 16, 10, 170, 103, "12:16:10.170103", "\190\216\123\113\069\145\229\064" ; 5, 51, 3, 639, 731, "05:51:03.639731", "\207\074\090\241\232\145\212\064" ; 23, 14, 37, 958, 429, "23:14:37.958429", "\169\165\185\085\223\109\244\064" ; 17, 44, 26, 93, 664, "17:44:26.093664", "\026\165\075\255\066\047\239\064" ; 1, 52, 58, 120, 599, "01:52:58.120599", "\238\120\147\223\030\122\186\064" ; 22, 53, 20, 44, 0, "22:53:20.044000", "\016\088\057\180\000\030\244\064" ; 0, 46, 37, 229, 762, "00:46:37.229762", "\186\103\093\163\117\218\165\064" ; 0, 27, 46, 589, 818, "00:27:46.589818", "\094\242\063\249\091\010\154\064" ; 14, 34, 59, 843, 832, "14:34:59.843832", "\106\247\171\000\123\162\233\064" ; 7, 53, 27, 185, 789, "07:53:27.185789", "\190\139\247\227\203\189\219\064" ; 3, 16, 6, 644, 563, "03:16:06.644563", "\155\086\010\129\082\251\198\064" ; 6, 23, 16, 887, 370, "06:23:16.887370", "\093\138\171\202\056\117\214\064" ; 10, 38, 58, 502, 838, "10:38:58.502838", "\166\183\063\023\080\184\226\064" ; 19, 42, 46, 570, 904, "19:42:46.570904", "\147\059\108\034\105\083\241\064" ; 14, 37, 47, 18, 687, "14:37:47.018687", "\187\122\021\153\096\183\233\064" ; 12, 36, 42, 145, 559, "12:36:42.145559", "\020\089\107\168\068\043\230\064" ; 14, 51, 40, 429, 511, "14:51:40.429511", "\072\218\141\190\141\031\234\064" ; 12, 8, 2, 996, 645, "12:08:02.996645", "\023\014\132\228\095\084\229\064" ; 10, 3, 34, 856, 560, "10:03:34.856560", "\098\132\240\104\219\174\225\064" ; 10, 6, 24, 289, 416, "10:06:24.289416", "\222\087\229\066\009\196\225\064" ; 23, 11, 23, 443, 432, "23:11:23.443432", "\032\039\076\024\183\097\244\064" ; 8, 22, 26, 471, 379, "08:22:26.471379", "\066\211\018\043\158\112\221\064" ; 0, 49, 18, 419, 697, "00:49:18.419697", "\117\114\134\226\214\028\167\064" ; 2, 51, 13, 760, 133, "02:51:13.760133", "\206\195\009\076\225\016\196\064" ; 18, 11, 17, 116, 581, "18:11:17.116581", "\203\019\008\187\163\248\239\064" ; 8, 23, 54, 727, 629, "08:23:54.727629", "\167\057\121\145\174\134\221\064" ; 11, 38, 25, 924, 747, "11:38:25.924747", "\066\005\135\151\061\118\228\064" ; 6, 50, 43, 780, 476, "06:50:43.780476", "\212\155\081\243\241\016\216\064" ; 3, 57, 0, 314, 378, "03:57:00.314378", "\075\206\137\061\040\198\203\064" ; 9, 35, 38, 170, 185, "09:35:38.170185", "\040\208\039\114\069\221\224\064" ; 9, 44, 47, 818, 553, "09:44:47.818553", "\161\015\150\049\250\033\225\064" ; 3, 0, 53, 251, 873, "03:00:53.251873", "\224\220\095\061\160\050\197\064" ; 3, 18, 31, 370, 971, "03:18:31.370971", "\098\076\250\123\175\067\199\064" ; 8, 13, 45, 875, 105, "08:13:45.875105", "\228\102\184\001\120\238\220\064" ; 4, 42, 56, 184, 972, "04:42:56.184972", "\172\204\148\214\011\148\208\064" ; 13, 10, 59, 188, 925, "13:10:59.188925", "\013\113\172\011\102\044\231\064" ; 4, 29, 26, 195, 149, "04:29:26.195149", "\108\118\164\250\024\147\207\064" ; 4, 56, 45, 276, 291, "04:56:45.276291", "\076\114\192\174\081\099\209\064" ; 18, 13, 23, 676, 729, "18:13:23.676729", "\181\201\225\211\058\004\240\064" ; 12, 21, 53, 132, 536, "12:21:53.132536", "\049\035\188\061\036\188\229\064" ; 0, 26, 51, 587, 990, "00:26:51.587990", "\128\241\012\026\090\046\153\064" ; 14, 26, 19, 492, 532, "14:26:19.492532", "\007\120\210\194\111\097\233\064" ; 7, 17, 30, 761, 633, "07:17:30.761633", "\163\086\152\190\176\162\217\064" ; 0, 54, 38, 210, 895, "00:54:38.210895", "\200\239\109\250\107\156\169\064" ; 18, 21, 45, 216, 863, "18:21:45.216863", "\075\086\069\120\147\035\240\064" ; 6, 47, 27, 897, 566, "06:47:27.897566", "\000\170\184\113\249\223\215\064" ; 7, 50, 19, 995, 752, "07:50:19.995752", "\187\152\102\186\255\142\219\064" ; 7, 19, 17, 360, 902, "07:19:17.360902", "\196\179\004\025\087\189\217\064" ; 18, 35, 25, 193, 947, "18:35:25.193947", "\098\043\104\026\211\086\240\064" ; 18, 32, 9, 586, 466, "18:32:09.586466", "\035\044\042\098\153\074\240\064" ; 18, 33, 56, 842, 96, "18:33:56.842096", "\194\167\057\121\077\081\240\064" ; 6, 6, 16, 866, 68, "06:06:16.866068", "\008\122\168\109\055\118\213\064" ; 15, 48, 48, 63, 751, "15:48:48.063751", "\131\137\063\010\002\204\235\064" ; 7, 20, 53, 933, 646, "07:20:53.933646", "\003\039\219\192\123\213\217\064" ; 22, 50, 23, 806, 15, "22:50:23.806015", "\017\252\111\229\252\018\244\064" ; 22, 11, 45, 433, 812, "22:11:45.433812", "\010\218\228\240\022\130\243\064" ; 17, 25, 41, 917, 559, "17:25:41.917559", "\037\177\164\092\189\162\238\064" ; 12, 5, 24, 846, 328, "12:05:24.846328", "\054\117\030\021\155\064\229\064" ; 7, 27, 7, 92, 917, "07:27:07.092917", "\016\037\090\242\197\050\218\064" ; 15, 39, 13, 699, 737, "15:39:13.699737", "\090\217\062\100\054\132\235\064" ; 11, 52, 14, 11, 432, "11:52:14.011432", "\068\164\166\093\192\221\228\064" ; 1, 24, 46, 462, 248, "01:24:46.462248", "\165\138\226\085\118\222\179\064" ; 10, 12, 11, 506, 904, "10:12:11.506904", "\199\188\142\056\112\239\225\064" ; 9, 39, 58, 327, 395, "09:39:58.327395", "\060\020\005\122\202\253\224\064" ; 19, 23, 14, 259, 98, "19:23:14.259098", "\200\241\067\037\036\010\241\064" ; 16, 57, 3, 855, 579, "16:57:03.855579", "\005\054\231\096\251\203\237\064" ; 17, 2, 34, 316, 835, "17:02:34.316835", "\103\039\131\035\074\245\237\064" ; 16, 27, 48, 591, 470, "16:27:48.591470", "\082\126\082\237\146\240\236\064" ; 14, 17, 55, 129, 214, "14:17:55.129214", "\006\102\133\034\100\034\233\064" ; 5, 33, 17, 934, 885, "05:33:17.934885", "\034\229\039\213\123\135\211\064" ; 1, 38, 36, 207, 269, "01:38:36.207269", "\122\200\148\015\053\028\183\064" ; 7, 57, 11, 787, 885, "07:57:11.787885", "\001\053\181\108\242\245\219\064" ; 3, 5, 49, 273, 210, "03:05:49.273210", "\120\151\139\248\162\198\197\064" ; 0, 23, 59, 168, 477, "00:23:59.168477", "\131\020\060\133\172\124\150\064" ; 14, 3, 23, 215, 409, "14:03:23.215409", "\072\106\161\228\102\181\232\064" ; 16, 43, 59, 703, 743, "16:43:59.703743", "\057\010\016\133\246\105\237\064" ; 10, 3, 10, 984, 80, "10:03:10.984080", "\020\087\149\125\223\171\225\064" ; 20, 34, 11, 290, 947, "20:34:11.290947", "\157\010\184\167\052\020\242\064" ; 16, 28, 26, 812, 1, "16:28:26.812001", "\106\133\233\251\089\245\236\064" ; 15, 8, 1, 342, 159, "15:08:01.342159", "\097\110\247\242\042\154\234\064" ; 19, 31, 2, 213, 870, "19:31:02.213870", "\250\242\002\108\099\039\241\064" ; 19, 29, 52, 5, 124, "19:29:52.005124", "\071\231\252\020\000\035\241\064" ; 2, 5, 44, 88, 574, "02:05:44.088574", "\070\033\201\172\022\120\189\064" ; 8, 42, 21, 733, 25, "08:42:21.733025", "\138\176\225\233\110\155\222\064" ; 20, 40, 5, 817, 663, "20:40:05.817663", "\066\204\037\021\093\042\242\064" ; 1, 57, 33, 673, 737, "01:57:33.673737", "\027\045\007\122\172\141\187\064" ; 10, 27, 32, 686, 596, "10:27:32.686596", "\178\044\152\248\149\098\226\064" ; 20, 22, 53, 654, 490, "20:22:53.654490", "\153\129\202\120\218\233\241\064" ; 16, 59, 57, 156, 939, "16:59:57.156939", "\015\240\164\005\165\225\237\064" ; 0, 4, 18, 806, 336, "00:04:18.806336", "\102\217\147\192\230\044\112\064" ; 19, 41, 2, 961, 27, "19:41:02.961027", "\249\216\093\096\239\076\241\064" ; 7, 42, 33, 295, 949, "07:42:33.295949", "\018\019\212\240\082\026\219\064" ; 18, 28, 59, 747, 479, "18:28:59.747479", "\055\138\172\245\187\062\240\064" ; 17, 4, 50, 843, 527, "17:04:50.843527", "\201\085\044\254\090\006\238\064" ; 1, 55, 18, 429, 477, "01:55:18.429477", "\098\101\052\242\109\006\187\064" ; 5, 56, 54, 808, 951, "05:56:54.808951", "\069\106\218\197\179\233\212\064" ; 21, 47, 32, 106, 170, "21:47:32.106170", "\093\080\223\178\065\039\243\064" ; 20, 10, 59, 152, 982, "20:10:59.152982", "\238\064\157\114\050\189\241\064" ; 17, 30, 53, 850, 466, "17:30:53.850466", "\011\121\004\055\187\201\238\064" ; 0, 23, 0, 424, 750, "00:23:00.424750", "\231\251\169\241\178\145\149\064" ; 23, 17, 0, 224, 93, "23:17:00.224093", "\164\138\226\149\195\118\244\064" ; 2, 8, 55, 152, 934, "02:08:55.152934", "\114\192\174\038\039\055\190\064" ; 1, 42, 17, 200, 120, "01:42:17.200120", "\070\119\016\059\051\249\183\064" ; 20, 27, 58, 462, 350, "20:27:58.462350", "\021\029\201\101\231\252\241\064" ; 2, 38, 39, 578, 601, "02:38:39.578601", "\055\250\152\015\202\151\194\064" ; 10, 18, 10, 956, 363, "10:18:10.956363", "\003\148\134\154\094\028\226\064" ; 12, 24, 42, 350, 16, "12:24:42.350016", "\034\193\084\051\075\209\229\064" ; 6, 49, 45, 170, 963, "06:49:45.170963", "\116\203\014\241\074\002\216\064" ; 5, 22, 48, 201, 750, "05:22:48.201750", "\254\212\120\233\012\234\210\064" ; 11, 11, 32, 142, 413, "11:11:32.142413", "\049\181\165\142\132\172\227\064" ; 0, 51, 25, 857, 701, "00:51:25.857701", "\126\225\149\036\183\027\168\064" ; 13, 48, 8, 456, 569, "13:48:08.456569", "\108\151\054\156\014\067\232\064" ; 17, 46, 52, 630, 731, "17:46:52.630731", "\050\199\242\046\148\065\239\064" ; 11, 55, 17, 956, 536, "11:55:17.956536", "\174\098\241\155\190\244\228\064" ; 2, 11, 22, 141, 931, "02:11:22.141931", "\073\011\151\085\036\202\190\064" ; 6, 31, 23, 929, 469, "06:31:23.929469", "\105\139\107\124\251\238\214\064" ; 16, 56, 21, 438, 47, "16:56:21.438047", "\100\036\123\004\174\198\237\064" ; 1, 5, 58, 776, 290, "01:05:58.776290", "\108\004\226\117\141\237\174\064" ; 0, 3, 30, 724, 697, "00:03:30.724697", "\076\080\195\183\048\087\106\064" ; 6, 37, 58, 699, 23, "06:37:58.699023", "\010\247\202\188\172\081\215\064" ; 5, 52, 55, 118, 196, "05:52:55.118196", "\161\244\133\144\199\173\212\064" ; 2, 11, 8, 422, 581, "02:11:08.422581", "\233\182\068\046\108\188\190\064" ; 3, 8, 41, 268, 220, "03:08:41.268220", "\017\112\008\085\162\028\198\064" ; 21, 51, 27, 400, 832, "21:51:27.400832", "\179\208\206\105\246\053\243\064" ; 11, 18, 48, 793, 979, "11:18:48.793979", "\214\165\070\104\025\227\227\064" ; 10, 37, 8, 297, 745, "10:37:08.297745", "\177\133\032\135\137\170\226\064" ; 3, 30, 4, 840, 570, "03:30:04.840570", "\000\058\204\151\107\158\200\064" ; 17, 19, 29, 344, 245, "17:19:29.344245", "\026\023\014\004\043\116\238\064" ; 22, 45, 56, 343, 16, "22:45:56.343016", "\096\088\254\124\069\002\244\064" ; 9, 25, 53, 121, 132, "09:25:53.121132", "\080\055\080\224\035\148\224\064" ; 12, 19, 7, 129, 710, "12:19:07.129710", "\255\149\149\038\100\167\229\064" ; 14, 4, 51, 819, 476, "14:04:51.819476", "\124\187\037\057\122\192\232\064" ; 2, 25, 52, 394, 248, "02:25:52.394248", "\066\237\183\118\050\024\193\064" ; 18, 7, 33, 447, 806, "18:07:33.447806", "\158\063\109\084\174\220\239\064" ; 3, 35, 48, 788, 173, "03:35:48.788173", "\076\085\218\226\100\074\201\064" ; 5, 50, 29, 630, 637, "05:50:29.630637", "\170\074\091\092\104\137\212\064" ; 11, 46, 24, 994, 299, "11:46:24.994299", "\238\034\076\209\031\178\228\064" ; 3, 19, 21, 504, 681, "03:19:21.504681", "\245\018\099\153\192\092\199\064" ; 8, 7, 34, 400, 120, "08:07:34.400120", "\159\234\144\155\153\145\220\064" ; 2, 19, 44, 223, 246, "02:19:44.223246", "\123\046\083\147\028\096\192\064" ; 15, 47, 8, 671, 9, "15:47:08.671009", "\203\221\231\120\149\191\235\064" ; 19, 7, 28, 673, 170, "19:07:28.673170", "\234\231\077\197\010\207\240\064" ; 23, 1, 42, 44, 369, "23:01:42.044369", "\191\068\188\181\096\061\244\064" ; 12, 52, 1, 539, 790, "12:52:01.539790", "\150\173\245\069\049\158\230\064" ; 10, 34, 19, 676, 519, "10:34:19.676519", "\132\044\011\166\117\149\226\064" ; 3, 14, 10, 662, 536, "03:14:10.662536", "\054\202\250\205\084\193\198\064" ; 15, 13, 47, 433, 492, "15:13:47.433492", "\098\157\042\223\109\197\234\064" ; 19, 23, 44, 217, 757, "19:23:44.217757", "\152\195\238\123\003\012\241\064" ; 23, 6, 58, 854, 582, "23:06:58.854582", "\220\044\094\172\045\081\244\064" ; 23, 33, 3, 773, 229, "23:33:03.773229", "\053\095\037\095\252\178\244\064" ; 18, 34, 17, 475, 341, "18:34:17.475341", "\024\042\255\154\151\082\240\064" ; 20, 20, 29, 257, 164, "20:20:29.257164", "\155\255\087\029\212\224\241\064" ; 2, 22, 48, 795, 181, "02:22:48.795181", "\179\178\125\200\101\188\192\064" ; 12, 24, 24, 224, 223, "12:24:24.224223", "\129\182\213\044\007\207\229\064" ; 13, 59, 47, 785, 917, "13:59:47.785917", "\140\104\059\038\121\154\232\064" ; 16, 1, 43, 85, 148, "16:01:43.085148", "\106\076\136\185\226\044\236\064" ; 3, 0, 40, 182, 317, "03:00:40.182317", "\065\216\041\086\023\044\197\064" ; 23, 33, 6, 416, 175, "23:33:06.416175", "\230\029\167\168\038\179\244\064" ; 12, 4, 11, 112, 552, "12:04:11.112552", "\227\166\006\154\099\055\229\064" ; 17, 10, 37, 562, 10, "17:10:37.562010", "\065\101\252\251\177\049\238\064" ; 7, 40, 20, 545, 35, "07:40:20.545035", "\011\123\218\225\034\249\218\064" ; 10, 9, 36, 181, 999, "10:09:36.181999", "\029\145\239\210\005\220\225\064" ; 7, 1, 25, 110, 525, "07:01:25.110525", "\025\115\215\018\071\177\216\064" ; 16, 46, 42, 69, 547, "16:46:42.069547", "\082\161\186\057\066\126\237\064" ; 13, 1, 26, 361, 351, "13:01:26.361351", "\236\248\047\144\203\228\230\064" ; 8, 25, 26, 614, 953, "08:25:26.614953", "\229\211\099\091\167\157\221\064" ; 18, 51, 0, 642, 164, "18:51:00.642164", "\043\194\077\070\074\145\240\064" ; 12, 21, 30, 634, 382, "12:21:30.634382", "\229\122\219\076\084\185\229\064" ; 19, 11, 30, 260, 658, "19:11:30.260658", "\023\185\167\043\036\222\240\064" ; 3, 15, 10, 261, 532, "03:15:10.261532", "\110\109\225\121\033\223\198\064" ; 0, 13, 57, 807, 538, "00:13:57.807538", "\056\162\123\214\117\046\138\064" ; 19, 7, 21, 755, 159, "19:07:21.755159", "\133\154\033\021\156\206\240\064" ; 1, 52, 40, 293, 278, "01:52:40.293278", "\163\090\068\020\075\104\186\064" ; 0, 34, 47, 855, 994, "00:34:47.855994", "\037\119\216\068\182\079\160\064" ; 15, 18, 5, 959, 455, "15:18:05.959455", "\224\248\218\179\190\229\234\064" ; 16, 56, 1, 276, 601, "16:56:01.276601", "\033\087\234\217\040\196\237\064" ; 15, 12, 47, 214, 907, "15:12:47.214907", "\022\165\132\224\230\189\234\064" ; 22, 29, 57, 711, 231, "22:29:57.711231", "\206\193\051\097\091\198\243\064" ; 10, 5, 30, 863, 544, "10:05:30.863544", "\213\006\039\162\091\189\225\064" ; 7, 34, 54, 232, 461, "07:34:54.232461", "\038\026\164\224\142\167\218\064" ; 10, 54, 8, 149, 931, "10:54:08.149931", "\181\024\060\204\004\042\227\064" ; 0, 56, 15, 13, 647, "00:56:15.013647", "\096\085\189\252\006\094\170\064" ; 22, 47, 58, 429, 815, "22:47:58.429815", "\134\177\133\224\230\009\244\064" ; 13, 42, 43, 53, 448, "13:42:43.053448", "\129\148\216\181\097\026\232\064" ; 18, 32, 40, 158, 91, "18:32:40.158091", "\172\109\138\135\130\076\240\064" ; 20, 54, 7, 24, 272, "20:54:07.024272", "\100\009\107\099\240\094\242\064" ; 0, 5, 0, 700, 130, "00:05:00.700130", "\045\207\131\187\051\203\114\064" ; 1, 32, 22, 360, 877, "01:32:22.360877", "\225\096\111\098\092\166\181\064" ; 14, 45, 41, 754, 816, "14:45:41.754816", "\080\226\115\039\184\242\233\064" ; 14, 37, 13, 566, 792, "14:37:13.566792", "\244\249\040\035\050\179\233\064" ; 16, 41, 15, 819, 55, "16:41:15.819055", "\212\212\178\053\122\085\237\064" ; 3, 28, 41, 371, 461, "03:28:41.371461", "\094\183\008\140\175\116\200\064" ; 2, 51, 29, 128, 808, "02:51:29.128808", "\188\209\199\124\144\024\196\064" ; 18, 40, 9, 937, 390, "18:40:09.937390", "\026\168\140\255\158\104\240\064" ; 19, 34, 11, 728, 548, "19:34:11.728548", "\153\242\033\168\059\051\241\064" ; 17, 17, 57, 138, 9, "17:17:57.138009", "\178\217\145\106\164\104\238\064" ; 12, 15, 18, 669, 433, "12:15:18.669433", "\060\193\254\107\213\138\229\064" ; 23, 46, 28, 450, 760, "23:46:28.450760", "\037\030\080\054\071\229\244\064" ; 23, 6, 12, 832, 277, "23:06:12.832277", "\003\176\001\081\077\078\244\064" ; 14, 4, 5, 125, 513, "14:04:05.125513", "\199\214\051\004\164\186\232\064" ; 19, 48, 55, 582, 263, "19:48:55.582263", "\234\001\243\080\121\106\241\064" ; 18, 0, 58, 845, 805, "18:00:58.845805", "\186\165\213\016\091\171\239\064" ; 22, 20, 36, 69, 948, "22:20:36.069948", "\071\203\129\030\065\163\243\064" ; 7, 1, 6, 128, 522, "07:01:06.128522", "\180\086\180\057\136\172\216\064" ; 3, 35, 54, 354, 656, "03:35:54.354656", "\170\040\094\101\045\077\201\064" ; 22, 26, 56, 406, 463, "22:26:56.406463", "\193\088\223\128\006\187\243\064" ; 22, 10, 4, 872, 950, "22:10:04.872950", "\081\107\154\247\205\123\243\064" ; 8, 1, 46, 256, 684, "08:01:46.256684", "\090\186\130\109\144\058\220\064" ; 21, 50, 29, 927, 768, "21:50:29.927768", "\036\066\035\216\094\050\243\064" ; 3, 2, 14, 413, 186, "03:02:14.413186", "\149\098\071\227\052\091\197\064" ; 10, 12, 18, 988, 0, "10:12:18.988000", "\014\045\178\157\095\240\225\064" ; 0, 31, 8, 22, 10, "00:31:08.022010", "\189\024\202\137\022\048\157\064" ; 9, 13, 45, 589, 818, "09:13:45.589818", "\147\255\201\223\050\057\224\064" ; 2, 46, 42, 972, 239, "02:46:42.972239", "\115\218\083\114\124\137\195\064" ; 8, 40, 28, 627, 918, "08:40:28.627918", "\165\250\206\047\040\127\222\064" ; 9, 54, 5, 28, 993, "09:54:05.028993", "\090\186\130\237\160\103\225\064" ; 2, 19, 50, 516, 822, "02:19:50.516822", "\237\041\057\039\066\099\192\064" ; 21, 11, 35, 395, 516, "21:11:35.395516", "\209\149\008\084\118\160\242\064" ; 19, 33, 45, 167, 636, "19:33:45.167636", "\026\022\163\174\146\049\241\064" ; 21, 6, 46, 770, 781, "21:06:46.770781", "\054\117\030\085\108\142\242\064" ; 5, 41, 8, 115, 318, "05:41:08.115318", "\169\191\094\097\007\253\211\064" ; 15, 23, 34, 49, 503, "15:23:34.049503", "\194\080\135\149\193\014\235\064" ; 16, 43, 37, 297, 974, "16:43:37.297974", "\034\197\000\137\041\103\237\064" ; 23, 19, 51, 278, 676, "23:19:51.278676", "\035\247\116\117\116\129\244\064" ; 6, 55, 13, 345, 419, "06:55:13.345419", "\027\075\088\027\086\084\216\064" ; 5, 31, 29, 539, 649, "05:31:29.539649", "\149\245\155\137\098\108\211\064" ; 3, 28, 33, 214, 762, "03:28:33.214762", "\054\059\082\125\155\112\200\064" ; 1, 57, 49, 782, 681, "01:57:49.782681", "\052\050\200\093\200\157\187\064" ; 0, 14, 12, 384, 884, "00:14:12.384884", "\008\006\016\062\020\163\138\064" ; 10, 20, 18, 481, 247, "10:20:18.481247", "\202\027\096\102\079\044\226\064" ; 14, 33, 38, 620, 746, "14:33:38.620746", "\036\183\038\221\083\152\233\064" ; 3, 29, 12, 37, 66, "03:29:12.037066", "\230\036\148\190\004\132\200\064" ; 20, 54, 16, 196, 902, "20:54:16.196902", "\040\182\130\038\131\095\242\064" ; 22, 54, 1, 648, 244, "22:54:01.648244", "\189\025\053\095\154\032\244\064" ; 0, 15, 40, 94, 612, "00:15:40.094612", "\122\174\239\195\193\096\141\064" ; 13, 9, 10, 465, 925, "13:09:10.465925", "\172\139\219\232\206\030\231\064" ; 21, 56, 27, 925, 73, "21:56:27.925073", "\151\088\025\205\190\072\243\064" ; 14, 49, 37, 862, 991, "14:49:37.862991", "\056\077\159\157\059\016\234\064" ; 7, 10, 26, 663, 497, "07:10:26.663497", "\000\031\188\118\170\056\217\064" ; 0, 11, 25, 182, 999, "00:11:25.182999", "\155\001\046\200\118\105\133\064" ; 7, 5, 47, 878, 636, "07:05:47.878636", "\070\125\146\059\248\242\216\064" ; 13, 36, 51, 747, 132, "13:36:51.747132", "\058\094\129\232\119\238\231\064" ; 18, 45, 57, 264, 797, "18:45:57.264797", "\113\199\155\060\084\126\240\064" ; 20, 17, 54, 235, 480, "20:17:54.235480", "\046\173\134\196\035\215\241\064" ; 14, 24, 4, 521, 282, "14:24:04.521282", "\192\150\087\174\144\080\233\064" ; 21, 47, 52, 740, 862, "21:47:52.740862", "\206\028\146\218\139\040\243\064" ; 17, 32, 48, 216, 173, "17:32:48.216173", "\169\163\227\234\006\216\238\064" ; 16, 29, 46, 187, 765, "16:29:46.187765", "\202\190\043\002\070\255\236\064" ; 23, 44, 44, 367, 448, "23:44:44.367448", "\112\039\017\225\197\222\244\064" ; 0, 30, 2, 9, 449, "00:30:02.009449", "\235\167\255\172\009\040\156\064" ; 4, 44, 31, 838, 743, "04:44:31.838743", "\176\030\247\173\245\171\208\064" ; 5, 56, 14, 780, 202, "05:56:14.780202", "\145\094\212\238\177\223\212\064" ; 10, 30, 38, 724, 640, "10:30:38.724640", "\172\057\064\048\215\121\226\064" ; 22, 53, 22, 544, 945, "22:53:22.544945", "\146\063\024\184\040\030\244\064" ; 21, 20, 41, 861, 252, "21:20:41.861252", "\090\045\176\199\157\194\242\064" ; 14, 16, 9, 434, 674, "14:16:09.434674", "\206\114\217\232\045\021\233\064" ; 0, 35, 5, 913, 950, "00:35:05.913950", "\092\032\065\241\211\115\160\064" ; 5, 5, 53, 156, 706, "05:05:53.156706", "\069\154\120\007\074\236\209\064" ; 8, 13, 58, 719, 588, "08:13:58.719588", "\166\211\186\013\174\241\220\064" ; 7, 44, 16, 840, 799, "07:44:16.840799", "\225\155\166\207\053\052\219\064" ; 21, 46, 18, 738, 555, "21:46:18.738555", "\053\012\031\209\171\034\243\064" ; 17, 16, 41, 158, 172, "17:16:41.158172", "\229\185\190\015\037\095\238\064" ; 4, 10, 49, 357, 935, "04:10:49.357935", "\140\103\208\208\173\100\205\064" ; 1, 21, 17, 880, 749, "01:21:17.880749", "\252\054\196\120\225\013\179\064" ; 18, 56, 55, 691, 646, "18:56:55.691646", "\103\101\251\016\123\167\240\064" ; 3, 47, 41, 740, 549, "03:47:41.740549", "\011\068\079\202\222\174\202\064" ; 14, 49, 39, 79, 485, "14:49:39.079485", "\112\032\036\139\098\016\234\064" ; 19, 54, 16, 493, 989, "19:54:16.493989", "\121\002\097\231\135\126\241\064" ; 11, 31, 46, 57, 186, "11:31:46.057186", "\249\187\119\212\065\068\228\064" ; 10, 22, 24, 781, 326, "10:22:24.781326", "\049\098\159\000\025\060\226\064" ; 11, 46, 43, 152, 442, "11:46:43.152442", "\145\011\206\224\100\180\228\064" ; 10, 57, 42, 384, 959, "10:57:42.384959", "\105\137\149\081\204\068\227\064" ; 10, 50, 46, 207, 984, "10:50:46.207984", "\195\015\206\167\198\016\227\064" ; 16, 22, 58, 464, 810, "16:22:58.464810", "\155\056\185\223\078\204\236\064" ; 19, 11, 21, 526, 934, "19:11:21.526934", "\146\088\082\110\152\221\240\064" ; 12, 49, 13, 324, 474, "12:49:13.324474", "\077\076\023\098\042\137\230\064" ; 0, 58, 40, 934, 662, "00:58:40.934662", "\161\133\004\140\222\129\171\064" ; 6, 52, 56, 934, 615, "06:52:56.934615", "\215\110\187\208\059\050\216\064" ; 2, 6, 31, 885, 246, "02:06:31.885246", "\234\090\123\159\226\167\189\064" ; 3, 42, 3, 114, 263, "03:42:03.114263", "\018\132\043\160\142\005\202\064" ; 11, 33, 17, 924, 75, "11:33:17.924075", "\002\188\005\146\189\079\228\064" ; 9, 50, 39, 442, 298, "09:50:39.442298", "\163\034\078\039\238\077\225\064" ; 11, 40, 49, 238, 606, "11:40:49.238606", "\212\012\169\162\039\136\228\064" ; 14, 19, 26, 82, 981, "14:19:26.082981", "\038\197\199\167\194\045\233\064" ; 23, 2, 38, 770, 367, "23:02:38.770367", "\239\088\108\083\236\064\244\064" ; 17, 30, 52, 313, 382, "17:30:52.313382", "\037\176\057\007\138\201\238\064" ; 5, 38, 37, 568, 238, "05:38:37.568238", "\150\234\002\094\100\215\211\064" ; 23, 33, 41, 819, 291, "23:33:41.819291", "\047\225\208\027\093\181\244\064" ; 8, 44, 53, 561, 226, "08:44:53.561226", "\235\116\032\235\099\193\222\064" ; 13, 47, 4, 635, 715, "13:47:04.635715", "\211\251\198\087\020\059\232\064" ; 1, 42, 59, 86, 842, "01:42:59.086842", "\236\253\070\059\022\035\184\064" ; 16, 36, 13, 206, 224, "16:36:13.206224", "\245\018\099\153\166\047\237\064" ; 3, 13, 52, 696, 190, "03:13:52.696190", "\231\000\193\028\089\184\198\064" ; 19, 36, 34, 140, 673, "19:36:34.140673", "\231\084\050\064\034\060\241\064" ; 13, 9, 13, 672, 921, "13:09:13.672921", "\249\158\145\136\053\031\231\064" ; 10, 20, 50, 693, 419, "10:20:50.693419", "\238\010\125\048\086\048\226\064" ; 13, 51, 31, 86, 383, "13:51:31.086383", "\254\071\166\195\098\092\232\064" ; 3, 29, 46, 565, 545, "03:29:46.565545", "\182\079\199\099\072\149\200\064" ; 8, 55, 7, 732, 765, "08:55:07.732765", "\170\043\159\229\238\090\223\064" ; 4, 47, 53, 328, 389, "04:47:53.328389", "\216\075\083\004\085\222\208\064" ; 13, 59, 37, 409, 426, "13:59:37.409426", "\004\142\004\026\045\153\232\064" ; 19, 17, 31, 918, 426, "19:17:31.918426", "\029\118\223\177\190\244\240\064" ; 5, 59, 40, 584, 837, "05:59:40.584837", "\031\043\248\109\037\019\213\064" ; 14, 19, 3, 720, 287, "14:19:03.720287", "\152\082\151\012\247\042\233\064" ; 17, 7, 30, 139, 409, "17:07:30.139409", "\249\220\009\118\068\026\238\064" ; 15, 3, 18, 794, 33, "15:03:18.794033", "\222\228\183\104\217\118\234\064" ; 10, 21, 5, 83, 741, "10:21:05.083741", "\011\155\001\174\034\050\226\064" ; 3, 58, 53, 40, 154, "03:58:53.040154", "\103\042\196\035\133\254\203\064" ; 20, 10, 13, 459, 741, "20:10:13.459741", "\250\096\025\091\087\186\241\064" ; 7, 7, 31, 368, 802, "07:07:31.368802", "\044\180\115\154\215\012\217\064" ; 23, 10, 49, 96, 866, "23:10:49.096866", "\226\092\195\140\145\095\244\064" ; 23, 1, 40, 852, 978, "23:01:40.852978", "\099\066\204\165\077\061\244\064" ; 23, 23, 55, 913, 437, "23:23:55.913437", "\159\029\112\157\190\144\244\064" ; 10, 47, 38, 7, 875, "10:47:38.007875", "\110\018\131\064\064\249\226\064" ; 20, 12, 39, 305, 808, "20:12:39.305808", "\237\237\150\228\116\195\241\064" ; 2, 49, 46, 430, 403, "02:49:46.430403", "\141\012\114\023\055\229\195\064" ; 7, 33, 15, 857, 136, "07:33:15.857136", "\014\244\080\219\246\142\218\064" ; 1, 19, 5, 354, 774, "01:19:05.354774", "\121\007\120\210\090\137\178\064" ; 20, 40, 35, 166, 423, "20:40:35.166423", "\229\041\171\169\050\044\242\064" ; 16, 33, 51, 274, 809, "16:33:51.274809", "\116\062\060\203\232\029\237\064" ; 12, 21, 52, 487, 98, "12:21:52.487098", "\126\139\078\150\015\188\229\064" ; 5, 47, 2, 106, 847, "05:47:02.106847", "\171\204\148\214\134\085\212\064" ; 15, 17, 55, 591, 451, "15:17:55.591451", "\198\165\042\237\114\228\234\064" ; 10, 17, 54, 316, 803, "10:17:54.316803", "\137\011\064\035\074\026\226\064" ; 9, 12, 19, 427, 546, "09:12:19.427546", "\242\242\116\174\109\046\224\064" ; 15, 9, 21, 62, 243, "15:09:21.062243", "\045\008\229\253\033\164\234\064" ; 17, 23, 49, 7, 925, "17:23:49.007925", "\250\237\235\064\160\148\238\064" ; 21, 45, 6, 103, 609, "21:45:06.103609", "\041\233\097\168\033\030\243\064" ; 11, 58, 3, 119, 691, "11:58:03.119691", "\084\056\130\212\099\009\229\064" ; 2, 24, 2, 387, 607, "02:24:02.387607", "\090\046\027\157\049\225\192\064" ; 15, 56, 23, 550, 483, "15:56:23.550483", "\065\134\142\157\241\004\236\064" ; 5, 36, 45, 648, 867, "05:36:45.648867", "\029\116\009\135\105\187\211\064" ; 8, 25, 57, 620, 989, "08:25:57.620989", "\139\165\072\190\103\165\221\064" ; 17, 33, 41, 265, 797, "17:33:41.265797", "\204\181\104\129\168\222\238\064" ; 10, 18, 1, 492, 103, "10:18:01.492103", "\104\202\078\191\047\027\226\064" ; 17, 34, 44, 936, 485, "17:34:44.936485", "\006\100\175\247\157\230\238\064" ; 9, 26, 56, 704, 148, "09:26:56.704148", "\241\098\097\136\022\156\224\064" ; 0, 19, 57, 746, 803, "00:19:57.746803", "\056\246\236\185\252\182\146\064" ; 20, 23, 49, 352, 655, "20:23:49.352655", "\188\145\121\164\085\237\241\064" ; 20, 28, 52, 446, 94, "20:28:52.446094", "\079\118\051\035\071\000\242\064" ; 5, 2, 45, 307, 101, "05:02:45.307101", "\229\243\138\167\083\189\209\064" ; 2, 10, 25, 227, 172, "02:10:25.227172", "\145\182\241\039\058\145\190\064" ; 15, 47, 35, 149, 648, "15:47:35.149648", "\061\154\234\201\228\194\235\064" ; 18, 11, 29, 167, 985, "18:11:29.167985", "\039\020\034\096\037\250\239\064" ; 9, 10, 12, 675, 6, "09:10:12.675006", "\212\046\166\153\149\030\224\064" ; 11, 43, 56, 577, 969, "11:43:56.577969", "\035\216\184\126\146\159\228\064" ; 12, 17, 38, 904, 954, "12:17:38.904954", "\077\023\098\245\092\156\229\064" ; 10, 39, 4, 99, 978, "10:39:04.099978", "\010\016\005\051\003\185\226\064" ; 17, 58, 5, 930, 226, "17:58:05.930226", "\252\080\105\196\189\149\239\064" ; 10, 47, 33, 130, 565, "10:47:33.130565", "\160\166\150\045\164\248\226\064" ; 10, 40, 11, 758, 69, "10:40:11.758069", "\100\235\025\066\120\193\226\064" ; 4, 47, 42, 669, 363, "04:47:42.669363", "\138\232\215\214\170\219\208\064" ; 7, 40, 15, 309, 677, "07:40:15.309677", "\213\122\191\209\211\247\218\064" ; 18, 19, 22, 369, 70, "18:19:22.369070", "\191\241\181\231\165\026\240\064" ; 10, 47, 5, 5, 159, "10:47:05.005159", "\009\053\067\042\032\245\226\064" ; 10, 59, 2, 127, 10, "10:59:02.127010", "\137\070\119\016\196\078\227\064" ; 13, 49, 0, 587, 630, "13:49:00.587630", "\005\110\221\205\146\073\232\064" ; 21, 32, 4, 249, 774, "21:32:04.249774", "\150\005\019\255\067\237\242\064" ; 20, 37, 41, 505, 998, "20:37:41.505998", "\222\091\145\024\088\033\242\064" ; 2, 35, 9, 690, 316, "02:35:09.690316", "\244\081\070\092\216\046\194\064" ; 3, 4, 58, 133, 339, "03:04:58.133339", "\036\154\064\017\017\173\197\064" ; 15, 51, 10, 495, 982, "15:51:10.495982", "\173\164\021\223\207\221\235\064" ; 10, 20, 51, 961, 668, "10:20:51.961668", "\052\248\251\197\126\048\226\064" ; 6, 47, 2, 333, 324, "06:47:02.333324", "\190\047\046\085\149\217\215\064" ; 2, 43, 26, 505, 478, "02:43:26.505478", "\108\203\128\179\064\039\195\064" ; 20, 1, 31, 731, 656, "20:01:31.731656", "\255\235\220\180\187\153\241\064" ; 9, 20, 25, 913, 140, "09:20:25.913140", "\149\096\113\056\061\107\224\064" ; 7, 3, 49, 668, 666, "07:03:49.668666", "\125\122\108\203\106\213\216\064" ; 17, 21, 45, 6, 234, "17:21:45.006234", "\068\165\017\051\032\133\238\064" ; 1, 57, 4, 128, 419, "01:57:04.128419", "\047\077\017\224\032\112\187\064" ; 23, 8, 16, 624, 891, "23:08:16.624891", "\137\180\141\255\009\086\244\064" ; 15, 35, 58, 371, 405, "15:35:58.371405", "\018\189\140\226\203\107\235\064" ; 5, 43, 38, 143, 132, "05:43:38.143132", "\193\030\019\041\137\034\212\064" ; 5, 12, 14, 96, 75, "05:12:14.096075", "\190\193\023\038\134\075\210\064" ; 11, 59, 17, 261, 579, "11:59:17.261579", "\074\236\218\094\168\018\229\064" ; 2, 37, 11, 741, 350, "02:37:11.741350", "\114\138\142\228\222\107\194\064" ; 8, 46, 37, 379, 738, "08:46:37.379738", "\195\156\160\077\088\219\222\064" ; 15, 33, 49, 347, 488, "15:33:49.347488", "\120\039\159\030\171\091\235\064" ; 19, 3, 23, 552, 372, "19:03:23.552372", "\179\005\132\214\184\191\240\064" ; 3, 4, 15, 179, 186, "03:04:15.179186", "\243\028\145\239\150\151\197\064" ; 23, 59, 6, 530, 150, "23:59:06.530150", "\000\145\126\123\168\020\245\064" ; 16, 10, 27, 278, 97, "16:10:27.278097", "\003\174\043\230\104\110\236\064" ; 9, 8, 15, 74, 822, "09:08:15.074822", "\097\027\241\100\226\015\224\064" ; 4, 19, 49, 197, 957, "04:19:49.197957", "\130\172\167\086\153\114\206\064" ; 16, 53, 57, 95, 146, "16:53:57.095146", "\203\159\111\011\163\180\237\064" ; 19, 32, 32, 627, 343, "19:32:32.627343", "\070\208\152\009\010\045\241\064" ; 12, 40, 53, 151, 227, "12:40:53.151227", "\104\001\218\214\164\074\230\064" ; 17, 38, 14, 631, 305, "17:38:14.631305", "\026\139\166\051\212\000\239\064" ; 21, 42, 0, 737, 12, "21:42:00.737012", "\076\024\205\202\139\018\243\064" ; 22, 8, 25, 642, 36, "22:08:25.642036", "\110\138\199\069\154\117\243\064" ; 16, 51, 42, 14, 867, "16:51:42.014867", "\218\091\202\121\192\163\237\064" ; 5, 32, 4, 217, 481, "05:32:04.217481", "\160\109\053\235\013\117\211\064" ; 1, 56, 29, 313, 343, "01:56:29.313343", "\110\049\063\055\080\077\187\064" ; 9, 7, 39, 298, 536, "09:07:39.298536", "\150\094\155\141\105\011\224\064" ; 22, 7, 45, 706, 705, "22:07:45.706705", "\239\230\169\078\027\115\243\064" ; 23, 19, 17, 494, 648, "23:19:17.494648", "\113\005\020\234\087\127\244\064" ; 3, 23, 25, 275, 795, "03:23:25.275795", "\179\036\064\077\163\214\199\064" ; 15, 38, 42, 292, 692, "15:38:42.292692", "\250\156\187\093\073\128\235\064" ; 0, 12, 20, 635, 973, "00:12:20.635973", "\029\033\003\121\022\037\135\064" ; 0, 57, 20, 688, 470, "00:57:20.688470", "\142\204\035\127\096\225\170\064" ; 18, 25, 59, 974, 454, "18:25:59.974454", "\215\019\093\151\127\051\240\064" ; 6, 43, 13, 778, 863, "06:43:13.778863", "\068\050\228\216\113\160\215\064" ; 7, 9, 43, 978, 881, "07:09:43.978881", "\107\126\252\165\254\045\217\064" ; 12, 1, 14, 364, 490, "12:01:14.364490", "\183\238\230\169\075\033\229\064" ; 7, 32, 8, 562, 237, "07:32:08.562237", "\231\229\176\251\035\126\218\064" ; 1, 8, 20, 672, 247, "01:08:20.672247", "\213\031\097\024\172\004\176\064" ; 16, 27, 19, 640, 333, "16:27:19.640333", "\178\161\155\125\244\236\236\064" ; 7, 52, 11, 395, 718, "07:52:11.395718", "\028\151\113\083\217\170\219\064" ; 12, 17, 57, 415, 763, "12:17:57.415763", "\252\052\238\077\173\158\229\064" ; 15, 41, 53, 146, 342, "15:41:53.146342", "\001\107\213\174\036\152\235\064" ; 6, 25, 39, 919, 912, "06:25:39.919912", "\205\148\214\223\250\152\214\064" ; 10, 9, 10, 375, 771, "10:09:10.375771", "\121\231\080\006\204\216\225\064" ; 15, 3, 21, 995, 127, "15:03:21.995127", "\012\148\020\216\063\119\234\064" ; 20, 8, 6, 968, 904, "20:08:06.968904", "\015\123\161\128\111\178\241\064" ; 7, 44, 26, 845, 486, "07:44:26.845486", "\207\079\113\028\182\054\219\064" ; 19, 4, 17, 667, 720, "19:04:17.667720", "\174\042\251\174\026\195\240\064" ; 17, 42, 49, 19, 713, "17:42:49.019713", "\074\040\125\161\032\035\239\064" ; 5, 57, 51, 888, 482, "05:57:51.888482", "\069\155\227\220\248\247\212\064" ; 15, 53, 4, 924, 528, "15:53:04.924528", "\135\190\187\149\029\236\235\064" ; 8, 52, 54, 789, 159, "08:52:54.789159", "\022\192\148\129\178\057\223\064" ; 20, 51, 34, 777, 734, "20:51:34.777734", "\240\052\153\113\108\085\242\064" ; 1, 52, 20, 696, 433, "01:52:20.696433", "\219\222\110\073\178\084\186\064" ; 6, 16, 9, 572, 419, "06:16:09.572419", "\039\077\131\162\100\010\214\064" ; 7, 34, 57, 129, 865, "07:34:57.129865", "\250\073\181\079\072\168\218\064" ; 13, 28, 44, 851, 158, "13:28:44.851158", "\184\179\175\060\155\177\231\064" ; 23, 25, 47, 739, 625, "23:25:47.739625", "\037\006\129\213\187\151\244\064" ; 13, 29, 59, 854, 698, "13:29:59.854698", "\191\158\175\089\251\186\231\064" ; 8, 36, 8, 283, 45, "08:36:08.283045", "\147\198\104\029\018\062\222\064" ; 9, 55, 15, 207, 689, "09:55:15.207689", "\216\102\099\165\102\112\225\064" ; 16, 49, 33, 592, 116, "16:49:33.592116", "\238\064\157\242\178\147\237\064" ; 16, 8, 2, 847, 621, "16:08:02.847621", "\077\019\182\031\091\092\236\064" ; 16, 56, 41, 591, 185, "16:56:41.591185", "\028\206\252\234\050\201\237\064" ; 5, 41, 10, 319, 274, "05:41:10.319274", "\030\055\252\110\148\253\211\064" ; 11, 10, 31, 520, 260, "11:10:31.520260", "\173\076\248\165\240\164\227\064" ; 4, 29, 20, 923, 285, "04:29:20.923285", "\242\239\051\046\118\144\207\064" ; 9, 22, 46, 936, 799, "09:22:46.936799", "\126\229\065\250\221\124\224\064" ; 4, 46, 35, 325, 250, "04:46:35.325250", "\066\096\229\208\212\202\208\064" ; 4, 54, 25, 238, 179, "04:54:25.238179", "\230\033\083\062\079\064\209\064" ; 1, 22, 45, 95, 969, "01:22:45.095969", "\110\164\108\145\024\101\179\064" ; 20, 14, 43, 261, 218, "20:14:43.261218", "\242\236\242\045\052\203\241\064" ; 16, 19, 58, 94, 806, "16:19:58.094806", "\174\151\166\008\195\181\236\064" ; 22, 54, 3, 484, 617, "22:54:03.484617", "\097\193\253\192\183\032\244\064" ; 19, 47, 7, 374, 599, "19:47:07.374599", "\098\133\091\254\181\099\241\064" ; 6, 52, 20, 285, 342, "06:52:20.285342", "\139\023\011\067\018\041\216\064" ; 5, 11, 19, 267, 738, "05:11:19.267738", "\121\144\158\034\209\061\210\064" ; 21, 47, 24, 828, 916, "21:47:24.828916", "\114\108\061\067\205\038\243\064" ; 18, 43, 30, 817, 106, "18:43:30.817106", "\182\189\221\018\045\117\240\064" ; 2, 47, 17, 625, 381, "02:47:17.625381", "\069\015\124\012\208\154\195\064" ; 1, 35, 29, 202, 402, "01:35:29.202402", "\165\018\158\208\051\097\182\064" ; 16, 28, 12, 957, 759, "16:28:12.957759", "\207\051\246\165\158\243\236\064" ; 8, 59, 52, 748, 553, "08:59:52.748553", "\149\215\074\232\047\162\223\064" ; 18, 1, 55, 326, 407, "18:01:55.326407", "\198\023\237\113\106\178\239\064" ; 23, 49, 43, 301, 455, "23:49:43.301455", "\100\122\194\210\116\241\244\064" ; 23, 17, 16, 848, 364, "23:17:16.848364", "\050\033\230\146\205\119\244\064" ; 20, 30, 30, 102, 670, "20:30:30.102670", "\068\076\137\164\097\006\242\064" ; 4, 23, 15, 721, 216, "04:23:15.721216", "\173\078\206\080\220\217\206\064" ; 19, 15, 41, 571, 747, "19:15:41.571747", "\169\046\224\037\217\237\240\064" ; 21, 52, 23, 135, 517, "21:52:23.135517", "\176\223\019\043\114\057\243\064" ; 17, 10, 53, 70, 945, "17:10:53.070945", "\218\114\046\069\162\051\238\064" ; 19, 26, 34, 793, 167, "19:26:34.793167", "\085\225\207\176\172\022\241\064" ; 5, 18, 37, 632, 983, "05:18:37.632983", "\252\032\203\130\104\171\210\064" ; 20, 18, 49, 370, 393, "20:18:49.370393", "\218\053\033\237\149\218\241\064" ; 8, 47, 23, 539, 455, "08:47:23.539455", "\171\067\110\134\226\230\222\064" ; 18, 31, 34, 118, 935, "18:31:34.118935", "\246\098\040\231\097\072\240\064" ; 8, 48, 22, 733, 33, "08:48:22.733033", "\121\062\003\234\174\245\222\064" ; 12, 29, 48, 156, 915, "12:29:48.156915", "\040\155\114\005\133\247\229\064" ; 7, 49, 45, 541, 69, "07:49:45.541069", "\249\222\223\160\098\134\219\064" ; 15, 45, 31, 350, 579, "15:45:31.350579", "\117\115\241\055\107\179\235\064" ; 23, 31, 44, 891, 335, "23:31:44.891335", "\045\125\232\066\014\174\244\064" ; 23, 8, 43, 360, 58, "23:08:43.360058", "\107\045\204\194\181\087\244\064" ; 8, 27, 5, 925, 767, "08:27:05.925767", "\046\059\196\063\123\182\221\064" ; 18, 11, 1, 879, 671, "18:11:01.879671", "\008\204\067\038\188\246\239\064" ; 16, 10, 9, 776, 87, "16:10:09.776087", "\123\103\180\213\056\108\236\064" ; 16, 18, 18, 88, 103, "16:18:18.088103", "\246\097\189\209\066\169\236\064" ; 20, 51, 6, 204, 887, "20:51:06.204887", "\070\151\055\071\163\083\242\064" ; 17, 13, 21, 16, 468, "17:13:21.016468", "\046\230\231\134\032\070\238\064" ; 11, 31, 29, 819, 770, "11:31:29.819770", "\136\075\142\059\058\066\228\064" ; 20, 36, 14, 527, 151, "20:36:14.527151", "\017\227\053\111\232\027\242\064" ; 7, 20, 58, 633, 217, "07:20:58.633217", "\146\152\160\134\168\214\217\064" ; 18, 57, 41, 135, 491, "18:57:41.135491", "\094\156\248\042\082\170\240\064" ; 1, 14, 28, 641, 807, "01:14:28.641807", "\088\171\118\077\164\116\177\064" ; 1, 13, 17, 977, 126, "01:13:17.977126", "\018\246\237\036\250\045\177\064" ; 1, 22, 39, 977, 451, "01:22:39.977451", "\113\142\058\058\250\095\179\064" ; 11, 32, 3, 310, 969, "11:32:03.310969", "\162\066\117\243\105\070\228\064" ; 2, 21, 11, 826, 864, "02:21:11.826864", "\030\247\173\214\233\139\192\064" ; 8, 34, 19, 811, 821, "08:34:19.811821", "\078\017\224\244\243\034\222\064" ; 8, 45, 4, 374, 776, "08:45:04.374776", "\213\121\084\252\023\196\222\064" ; 19, 43, 27, 153, 888, "19:43:27.153888", "\116\067\083\118\242\085\241\064" ; 22, 8, 13, 529, 442, "22:08:13.529442", "\178\044\152\120\216\116\243\064" ; 11, 24, 44, 571, 5, "11:24:44.571005", "\028\071\172\069\146\015\228\064" ; 6, 51, 42, 851, 532, "06:51:42.851532", "\223\018\128\127\182\031\216\064" ; 22, 44, 50, 986, 971, "22:44:50.986971", "\114\026\162\202\047\254\243\064" ; 11, 44, 35, 408, 874, "11:44:35.408874", "\070\237\126\021\109\164\228\064" ; 10, 42, 18, 716, 905, "10:42:18.716905", "\043\193\226\240\086\209\226\064" ; 11, 29, 28, 311, 148, "11:29:28.311148", "\135\166\236\244\009\051\228\064" ; 2, 5, 31, 347, 0, "02:05:31.347000", "\182\243\253\212\088\107\189\064" ; 8, 35, 47, 189, 472, "08:35:47.189472", "\224\042\079\032\204\056\222\064" ; 13, 34, 41, 645, 81, "13:34:41.645081", "\200\232\128\164\052\222\231\064" ; 9, 18, 5, 593, 507, "09:18:05.593507", "\094\100\002\254\178\089\224\064" ; 5, 7, 15, 349, 486, "05:07:15.349486", "\026\135\250\093\214\000\210\064" ; 15, 58, 33, 305, 877, "15:58:33.305877", "\243\143\190\201\041\021\236\064" ; 12, 17, 20, 703, 134, "12:17:20.703134", "\215\223\018\128\022\154\229\064" ; 6, 42, 40, 929, 1, "06:42:40.929001", "\061\156\192\116\059\152\215\064" ; 13, 10, 52, 562, 719, "13:10:52.562719", "\187\070\203\001\146\043\231\064" ; 19, 1, 42, 157, 601, "19:01:42.157601", "\078\160\136\133\098\185\240\064" ; 4, 48, 16, 117, 378, "04:48:16.117378", "\209\003\031\131\007\228\208\064" ; 16, 9, 50, 16, 415, "16:09:50.016415", "\006\192\120\134\192\105\236\064" ; 0, 41, 20, 978, 461, "00:41:20.978461", "\211\022\215\248\244\097\163\064" ; 9, 46, 38, 882, 801, "09:46:38.882801", "\252\225\231\063\220\047\225\064" ; 14, 57, 12, 28, 77, "14:57:12.028077", "\152\188\001\230\000\073\234\064" ; 13, 1, 43, 623, 99, "13:01:43.623099", "\101\080\109\240\243\230\230\064" ; 1, 43, 2, 691, 116, "01:43:02.691116", "\190\105\250\236\176\038\184\064" ; 12, 51, 41, 565, 663, "12:51:41.565663", "\178\074\233\025\178\155\230\064" ; 22, 37, 15, 213, 48, "22:37:15.213048", "\008\005\165\104\179\225\243\064" ; 8, 11, 5, 115, 490, "08:11:05.115490", "\065\043\048\100\071\198\220\064" ; 13, 7, 57, 664, 425, "13:07:57.664425", "\180\055\248\066\181\021\231\064" ; 3, 18, 37, 400, 956, "03:18:37.400956", "\145\181\134\082\179\070\199\064" ; 12, 21, 26, 624, 493, "12:21:26.624493", "\115\190\216\251\211\184\229\064" ; 19, 48, 52, 153, 421, "19:48:52.153421", "\025\148\105\116\066\106\241\064" ; 10, 1, 5, 628, 68, "10:01:05.628068", "\245\015\034\025\052\156\225\064" ; 4, 13, 49, 797, 90, "04:13:49.797090", "\252\140\011\007\230\190\205\064" ; 7, 58, 29, 910, 22, "07:58:29.910022", "\041\234\204\061\122\009\220\064" ; 5, 24, 40, 364, 494, "05:24:40.364494", "\102\164\222\083\023\006\211\064" ; 0, 56, 33, 619, 307, "00:56:33.619307", "\094\158\206\021\061\131\170\064" ; 15, 54, 21, 208, 379, "15:54:21.208379", "\197\111\010\171\166\245\235\064" ; 10, 13, 49, 259, 292, "10:13:49.259292", "\131\188\030\076\168\251\225\064" ; 8, 56, 33, 624, 89, "08:56:33.624089", "\051\253\018\241\103\112\223\064" ; 15, 46, 52, 253, 723, "15:46:52.253723", "\103\178\127\030\136\189\235\064" ; 18, 0, 1, 842, 887, "18:00:01.842887", "\103\040\238\248\058\164\239\064" ; 20, 15, 34, 721, 840, "20:15:34.721840", "\143\025\168\140\107\206\241\064" ; 8, 16, 14, 564, 365, "08:16:14.564365", "\128\096\142\030\164\019\221\064" ; 16, 36, 34, 992, 607, "16:36:34.992607", "\089\193\111\195\095\050\237\064" ; 1, 10, 39, 823, 905, "01:10:39.823905", "\003\038\112\235\210\143\176\064" ; 20, 37, 58, 947, 832, "20:37:58.947832", "\034\227\081\042\111\034\242\064" ; 15, 39, 40, 180, 828, "15:39:40.180828", "\070\205\087\201\133\135\235\064" ; 18, 7, 32, 304, 753, "18:07:32.304753", "\011\093\137\192\137\220\239\064" ; 17, 40, 1, 493, 946, "17:40:01.493946", "\128\215\103\206\047\014\239\064" ; 14, 3, 10, 870, 103, "14:03:10.870103", "\037\063\226\215\219\179\232\064" ; 10, 18, 13, 411, 397, "10:18:13.411397", "\150\010\042\042\173\028\226\064" ; 8, 33, 48, 328, 387, "08:33:48.328387", "\092\232\074\004\021\027\222\064" ; 2, 0, 39, 318, 758, "02:00:39.318758", "\087\209\031\154\081\071\188\064" ; 23, 48, 13, 125, 774, "23:48:13.125774", "\011\153\043\003\210\235\244\064" ; 22, 5, 53, 585, 232, "22:05:53.585232", "\202\058\028\093\025\108\243\064" ; 6, 23, 54, 227, 958, "06:23:54.227958", "\183\038\221\150\142\126\214\064" ; 20, 10, 44, 761, 807, "20:10:44.761807", "\110\137\092\048\076\188\241\064" ; 15, 56, 56, 163, 506, "15:56:56.163506", "\086\239\112\059\005\009\236\064" ; 9, 36, 46, 690, 524, "09:36:46.690524", "\164\201\197\024\214\229\224\064" ; 7, 16, 51, 828, 758, "07:16:51.828758", "\147\254\094\010\245\152\217\064" ; 9, 14, 0, 79, 812, "09:14:00.079812", "\058\229\209\141\002\059\224\064" ; 11, 57, 2, 827, 497, "11:57:02.827497", "\017\253\218\122\218\001\229\064" ; 23, 52, 16, 421, 350, "23:52:16.421350", "\099\127\217\189\006\251\244\064" ; 15, 14, 35, 343, 410, "15:14:35.343410", "\228\247\054\253\106\203\234\064" ; 2, 2, 21, 34, 614, "02:02:21.034614", "\251\141\118\220\008\173\188\064" ; 19, 2, 9, 762, 711, "19:02:09.762711", "\021\115\016\052\028\187\240\064" ; 9, 6, 0, 473, 643, "09:06:00.473643", "\191\186\042\080\030\254\223\064" ; 23, 49, 57, 843, 687, "23:49:57.843687", "\145\240\189\127\093\242\244\064" ; 1, 22, 42, 681, 23, "01:22:42.681023", "\210\248\133\087\174\098\179\064" ; 22, 48, 54, 116, 928, "22:48:54.116928", "\255\228\239\222\097\013\244\064" ; 3, 36, 42, 364, 720, "03:36:42.364720", "\025\028\037\175\046\101\201\064" ; 7, 58, 41, 144, 296, "07:58:41.144296", "\060\074\037\060\073\012\220\064" ; 16, 28, 57, 235, 940, "16:28:57.235940", "\250\010\210\140\039\249\236\064" ; 17, 9, 21, 362, 349, "17:09:21.362349", "\024\238\092\152\043\040\238\064" ; 6, 14, 46, 69, 251, "06:14:46.069251", "\014\191\155\110\132\245\213\064" ; 3, 52, 21, 538, 47, "03:52:21.538047", "\091\094\185\222\196\058\203\064" ; 5, 6, 24, 426, 894, "05:06:24.426894", "\055\054\059\082\027\244\209\064" ; 4, 55, 39, 662, 840, "04:55:39.662840", "\159\118\248\107\234\082\209\064" ; 17, 10, 12, 754, 515, "17:10:12.754515", "\043\164\252\036\152\046\238\064" ; 8, 47, 57, 873, 620, "08:47:57.873620", "\072\220\099\233\119\239\222\064" ; 18, 52, 35, 640, 222, "18:52:35.640222", "\131\108\089\062\058\151\240\064" ; 3, 39, 35, 573, 586, "03:39:35.573586", "\185\027\068\107\201\187\201\064" ; 5, 28, 51, 342, 80, "05:28:51.342080", "\040\131\163\228\213\068\211\064" ; 8, 54, 47, 428, 608, "08:54:47.428608", "\179\063\080\110\219\085\223\064" ; 7, 40, 5, 219, 482, "07:40:05.219482", "\004\059\254\011\078\245\218\064" ; 20, 38, 7, 986, 941, "20:38:07.986941", "\098\165\130\202\255\034\242\064" ; 19, 48, 3, 858, 348, "19:48:03.858348", "\201\028\203\187\061\103\241\064" ; 10, 39, 17, 401, 620, "10:39:17.401620", "\173\047\018\218\172\186\226\064" ; 19, 51, 30, 244, 909, "19:51:30.244909", "\024\179\037\235\035\116\241\064" ; 19, 55, 39, 796, 392, "19:55:39.796392", "\173\137\005\190\188\131\241\064" ; 4, 39, 40, 914, 326, "04:39:40.914326", "\249\050\081\132\058\099\208\064" ; 1, 42, 56, 463, 361, "01:42:56.463361", "\062\149\211\158\118\032\184\064" ; 18, 31, 37, 641, 797, "18:31:37.641797", "\091\238\204\068\154\072\240\064" ; 5, 26, 16, 558, 543, "05:26:16.558543", "\154\035\043\191\035\030\211\064" ; 21, 15, 20, 57, 816, "21:15:20.057816", "\083\120\208\236\128\174\242\064" ; 23, 39, 34, 875, 524, "23:39:34.875524", "\046\116\037\002\110\203\244\064" ; 7, 34, 19, 828, 254, "07:34:19.828254", "\178\016\029\002\245\158\218\064" ; 16, 21, 7, 92, 563, "16:21:07.092563", "\058\174\070\246\098\190\236\064" ; 3, 56, 12, 158, 964, "03:56:12.158964", "\159\174\238\088\020\174\203\064" ; 13, 25, 6, 613, 331, "13:25:06.613331", "\084\085\104\160\083\150\231\064" ; 8, 56, 25, 942, 813, "08:56:25.942813", "\079\086\012\087\124\110\223\064" ; 4, 30, 46, 882, 987, "04:30:46.882987", "\229\207\183\005\113\187\207\064" ; 21, 47, 7, 799, 813, "21:47:07.799813", "\095\183\008\204\188\037\243\064" ; 1, 55, 26, 793, 478, "01:55:26.793478", "\024\204\095\033\203\014\187\064" ; 8, 53, 5, 7, 94, "08:53:05.007094", "\128\100\058\116\064\060\223\064" ; 17, 48, 17, 169, 818, "17:48:17.169818", "\137\040\038\111\037\076\239\064" ; 1, 17, 17, 769, 412, "01:17:17.769412", "\039\081\047\248\196\029\178\064" ; 19, 41, 42, 662, 488, "19:41:42.662488", "\096\004\141\153\106\079\241\064" ; 5, 43, 57, 157, 290, "05:43:57.157290", "\127\019\010\017\074\039\212\064" ; 19, 36, 35, 275, 393, "19:36:35.275393", "\136\125\002\104\052\060\241\064" ; 1, 28, 26, 792, 55, "01:28:26.792055", "\163\209\029\196\202\186\180\064" ; 4, 46, 22, 355, 111, "04:46:22.355111", "\221\124\035\186\150\199\208\064" ; 18, 43, 11, 410, 462, "18:43:11.410462", "\036\154\064\145\246\115\240\064" ; 7, 12, 54, 107, 713, "07:12:54.107713", "\023\017\197\228\134\093\217\064" ; 10, 56, 41, 126, 888, "10:56:41.126888", "\072\108\119\015\036\061\227\064" ; 4, 10, 35, 786, 660, "04:10:35.786660", "\137\094\070\177\228\093\205\064" ; 21, 24, 15, 887, 726, "21:24:15.887726", "\157\045\032\052\254\207\242\064" ; 18, 3, 53, 390, 161, "18:03:53.390161", "\230\235\050\124\044\193\239\064" ; 20, 12, 31, 507, 335, "20:12:31.507335", "\018\078\011\030\248\194\241\064" ; 6, 17, 18, 713, 644, "06:17:18.713644", "\063\226\087\172\173\027\214\064" ; 0, 39, 0, 675, 432, "00:39:00.675432", "\088\029\057\210\089\073\162\064" ; 13, 41, 19, 547, 683, "13:41:19.547683", "\178\127\158\134\241\015\232\064" ; 7, 11, 48, 994, 535, "07:11:48.994535", "\238\032\118\166\063\077\217\064" ; 12, 20, 40, 716, 706, "12:20:40.716706", "\219\107\065\239\022\179\229\064" ; 4, 27, 49, 42, 449, "04:27:49.042449", "\095\005\248\110\133\098\207\064" ; 6, 4, 29, 488, 287, "06:04:29.488287", "\004\030\024\064\095\091\213\064" ; 17, 8, 38, 443, 337, "17:08:38.443337", "\131\019\209\047\206\034\238\064" ; 5, 22, 27, 237, 566, "05:22:27.237566", "\041\006\072\052\207\228\210\064" ; 22, 9, 40, 87, 836, "22:09:40.087836", "\183\184\198\103\065\122\243\064" ; 21, 43, 47, 931, 638, "21:43:47.931638", "\091\063\253\231\062\025\243\064" ; 20, 9, 33, 400, 181, "20:09:33.400181", "\055\049\036\103\214\183\241\064" ; 7, 50, 52, 259, 456, "07:50:52.259456", "\176\086\237\154\016\151\219\064" ; 17, 35, 27, 716, 475, "17:35:27.716475", "\173\250\092\237\246\235\238\064" ; 21, 8, 28, 847, 799, "21:08:28.847799", "\041\175\149\144\205\148\242\064" ; 15, 16, 1, 230, 115, "15:16:01.230115", "\235\033\026\093\039\214\234\064" ; 3, 6, 55, 429, 874, "03:06:55.429874", "\179\121\028\006\183\231\197\064" ; 12, 30, 21, 868, 894, "12:30:21.868894", "\054\202\250\205\187\251\229\064" ; 12, 0, 34, 794, 878, "12:00:34.794878", "\202\252\163\111\089\028\229\064" ; 11, 53, 59, 112, 341, "11:53:59.112341", "\032\039\076\152\227\234\228\064" ; 14, 54, 50, 512, 221, "14:54:50.512221", "\107\075\029\100\080\055\234\064" ; 5, 4, 1, 827, 513, "05:04:01.827513", "\001\022\249\245\116\208\209\064" ; 16, 5, 15, 463, 711, "16:05:15.463711", "\122\115\184\214\110\071\236\064" ; 13, 12, 46, 875, 138, "13:12:46.875138", "\048\104\033\001\220\057\231\064" ; 12, 6, 3, 530, 154, "12:06:03.530154", "\123\133\005\247\112\069\229\064" ; 11, 16, 33, 248, 275, "11:16:33.248275", "\173\105\222\241\039\210\227\064" ; 9, 45, 13, 189, 993, "09:45:13.189993", "\047\051\108\020\038\037\225\064" ; 18, 20, 29, 931, 420, "18:20:29.931420", "\109\168\024\231\222\030\240\064" ; 9, 53, 48, 618, 267, "09:53:48.618267", "\039\224\215\200\147\101\225\064" ; 4, 59, 58, 889, 763, "04:59:58.889763", "\140\130\224\241\184\147\209\064" ; 23, 29, 37, 637, 415, "23:29:37.637415", "\048\018\218\050\026\166\244\064" ; 17, 4, 32, 111, 440, "17:04:32.111440", "\111\158\234\144\003\004\238\064" ; 4, 32, 55, 712, 134, "04:32:55.712134", "\047\248\052\039\219\251\207\064" ; 18, 50, 41, 649, 437, "18:50:41.649437", "\061\013\024\100\026\144\240\064" ; 12, 55, 0, 275, 207, "12:55:00.275207", "\020\233\126\206\136\180\230\064" ; 22, 32, 6, 86, 613, "22:32:06.086613", "\038\080\196\098\097\206\243\064" ; 22, 39, 36, 293, 21, "22:39:36.293021", "\193\201\054\176\132\234\243\064" ; 4, 43, 17, 15, 327, "04:43:17.015327", "\240\024\030\251\064\153\208\064" ; 1, 53, 59, 648, 75, "01:53:59.648075", "\091\066\062\232\165\183\186\064" ; 15, 47, 28, 599, 204, "15:47:28.599204", "\245\221\173\044\019\194\235\064" ; 3, 49, 11, 849, 874, "03:49:11.849874", "\220\213\171\200\236\219\202\064" ; 10, 56, 10, 605, 775, "10:56:10.605775", "\184\064\130\098\083\057\227\064" ; 17, 16, 2, 583, 600, "17:16:02.583600", "\062\232\217\172\082\090\238\064" ; 5, 9, 55, 495, 724, "05:09:55.495724", "\246\039\241\185\223\040\210\064" ; 13, 8, 51, 907, 264, "13:08:51.907264", "\027\131\078\008\125\028\231\064" ; 9, 22, 45, 731, 80, "09:22:45.731080", "\088\226\001\101\183\124\224\064" ; 5, 12, 19, 473, 3, "05:12:19.473003", "\251\095\174\069\222\076\210\064" ; 12, 57, 33, 344, 824, "12:57:33.344824", "\092\087\204\008\171\199\230\064" ; 5, 30, 45, 194, 125, "05:30:45.194125", "\149\067\139\108\076\097\211\064" ; 2, 35, 44, 94, 927, "02:35:44.094927", "\064\100\145\038\012\064\194\064" ; 6, 38, 19, 358, 623, "06:38:19.358623", "\038\226\173\243\214\086\215\064" ; 22, 44, 1, 104, 44, "22:44:01.104044", "\150\010\042\170\017\251\243\064" ; 0, 5, 2, 669, 410, "00:05:02.669410", "\216\153\066\231\181\234\114\064" ; 18, 45, 46, 263, 509, "18:45:46.263509", "\148\054\085\055\164\125\240\064" ; 23, 23, 56, 507, 90, "23:23:56.507090", "\098\103\010\029\200\144\244\064" ; 22, 57, 40, 767, 62, "22:57:40.767062", "\193\205\226\069\076\046\244\064" ; 16, 6, 13, 831, 464, "16:06:13.831464", "\249\099\090\155\186\078\236\064" ; 2, 14, 53, 797, 104, "02:14:53.797104", "\130\251\001\015\204\157\191\064" ; 18, 33, 42, 888, 877, "18:33:42.888877", "\211\022\215\056\110\080\240\064" ; 2, 6, 44, 830, 65, "02:06:44.830065", "\142\204\035\127\212\180\189\064" ; 14, 6, 29, 21, 659, "14:06:29.021659", "\021\055\110\177\160\204\232\064" ; 12, 55, 36, 494, 342, "12:55:36.494342", "\097\080\166\209\015\185\230\064" ; 1, 25, 50, 857, 881, "01:25:50.857881", "\220\214\022\158\219\030\180\064" ; 1, 49, 16, 304, 714, "01:49:16.304714", "\162\152\188\001\078\156\185\064" ; 1, 29, 31, 162, 82, "01:29:31.162082", "\069\185\052\126\041\251\180\064" ; 20, 15, 43, 650, 574, "20:15:43.650574", "\090\072\192\104\250\206\241\064" ; 23, 17, 24, 70, 380, "23:17:24.070380", "\101\199\070\032\065\120\244\064" ; 0, 8, 38, 961, 728, "00:08:38.961728", "\046\029\115\158\177\055\128\064" ; 9, 52, 0, 738, 257, "09:52:00.738257", "\225\036\205\159\023\088\225\064" ; 12, 41, 34, 846, 786, "12:41:34.846786", "\022\244\222\024\219\079\230\064" ; 7, 34, 19, 663, 4, "07:34:19.663004", "\072\084\168\110\234\158\218\064" ; 11, 48, 30, 873, 503, "11:48:30.873503", "\063\144\188\243\219\193\228\064" ; 2, 12, 21, 691, 395, "02:12:21.691395", "\158\065\067\255\176\005\191\064" ; 13, 52, 58, 357, 239, "13:52:58.357239", "\188\123\128\110\075\103\232\064" ; 23, 42, 18, 875, 143, "23:42:18.875143", "\069\242\149\000\174\213\244\064" ; 9, 24, 38, 34, 971, "09:24:38.034971", "\170\128\123\030\193\138\224\064" ; 5, 3, 29, 876, 825, "05:03:29.876825", "\212\154\230\029\120\200\209\064" ; 16, 27, 55, 177, 58, "16:27:55.177058", "\240\137\117\170\101\241\236\064" ; 10, 48, 18, 805, 555, "10:48:18.805555", "\132\071\027\199\089\254\226\064" ; 20, 15, 1, 229, 729, "20:15:01.229729", "\224\080\248\172\083\204\241\064" ; 8, 4, 40, 855, 92, "08:04:40.855092", "\196\203\211\185\054\102\220\064" ; 1, 4, 13, 370, 93, "01:04:13.370093", "\245\102\212\124\189\026\174\064" ; 2, 47, 38, 209, 917, "02:47:38.209917", "\240\108\143\222\026\165\195\064" ; 3, 7, 12, 803, 334, "03:07:12.803334", "\226\004\166\211\102\240\197\064" ; 18, 6, 58, 21, 892, "18:06:58.021892", "\001\218\086\179\064\216\239\064" ; 19, 5, 31, 72, 504, "19:05:31.072504", "\077\244\249\040\177\199\240\064" ; 8, 30, 45, 848, 525, "08:30:45.848525", "\054\205\059\078\118\237\221\064" ; 2, 33, 3, 98, 208, "02:33:03.098208", "\026\106\020\146\140\239\193\064" ; 10, 30, 2, 850, 67, "10:30:02.850067", "\141\181\191\051\091\117\226\064" ; 19, 47, 41, 439, 660, "19:47:41.439660", "\150\236\216\008\215\101\241\064" ; 15, 44, 50, 766, 121, "15:44:50.766121", "\249\047\016\132\088\174\235\064" ; 8, 55, 24, 819, 837, "08:55:24.819837", "\195\155\053\120\052\095\223\064" ; 21, 19, 52, 584, 458, "21:19:52.584458", "\190\161\240\089\137\191\242\064" ; 2, 32, 6, 49, 785, "02:32:06.049785", "\107\217\090\095\006\211\193\064" ; 22, 15, 54, 972, 108, "22:15:54.972108", "\066\030\193\141\175\145\243\064" ; 19, 36, 27, 988, 215, "19:36:27.988215", "\038\136\186\207\191\059\241\064" ; 0, 59, 37, 800, 31, "00:59:37.800031", "\147\201\169\157\153\243\171\064" ; 12, 47, 19, 794, 689, "12:47:19.794689", "\048\160\023\110\249\122\230\064" ; 21, 50, 9, 701, 156, "21:50:09.701156", "\150\090\239\055\027\049\243\064" ; 15, 36, 21, 6, 241, "15:36:21.006241", "\093\083\032\051\160\110\235\064" ; 5, 58, 44, 39, 66, "05:58:44.039066", "\025\174\014\128\002\005\213\064" ; 19, 51, 32, 928, 595, "19:51:32.928595", "\068\110\134\219\078\116\241\064" ; 5, 49, 12, 79, 302, "05:49:12.079302", "\033\178\072\019\005\118\212\064" ; 14, 47, 10, 705, 931, "14:47:10.705931", "\200\155\252\150\214\253\233\064" ; 8, 2, 1, 290, 347, "08:02:01.290347", "\096\149\011\149\082\062\220\064" ; 3, 49, 2, 285, 403, "03:49:02.285403", "\151\227\021\136\036\215\202\064" ; 3, 11, 21, 502, 32, "03:11:21.502032", "\198\166\149\066\192\108\198\064" ; 19, 22, 32, 390, 499, "19:22:32.390499", "\034\225\123\063\134\007\241\064" ; 14, 42, 58, 372, 412, "14:42:58.372412", "\021\146\204\234\075\222\233\064" ; 9, 7, 28, 501, 700, "09:07:28.501700", "\140\040\237\013\016\010\224\064" ; 2, 11, 33, 765, 355, "02:11:33.765355", "\213\038\078\238\195\213\190\064" ; 6, 22, 14, 655, 2, "06:22:14.655002", "\052\130\141\235\169\101\214\064" ; 12, 39, 53, 670, 350, "12:39:53.670350", "\220\215\129\115\053\067\230\064" ; 20, 56, 55, 207, 330, "20:56:55.207330", "\023\067\057\081\115\105\242\064" ; 7, 17, 20, 458, 563, "07:17:20.458563", "\010\160\024\089\029\160\217\064" ; 20, 14, 24, 12, 972, "20:14:24.012972", "\188\032\034\053\000\202\241\064" ; 1, 30, 36, 675, 852, "01:30:36.675852", "\240\252\162\004\173\060\181\064" ; 7, 56, 40, 516, 488, "07:56:40.516488", "\050\175\035\014\033\238\219\064" ; 3, 31, 3, 796, 787, "03:31:03.796787", "\113\205\029\253\229\187\200\064" ; 14, 24, 47, 92, 114, "14:24:47.092114", "\048\015\153\242\226\085\233\064" ; 5, 10, 20, 962, 336, "05:10:20.962336", "\241\187\233\150\061\047\210\064" ; 8, 12, 11, 797, 572, "08:12:11.797572", "\013\110\107\011\243\214\220\064" ; 18, 52, 23, 382, 326, "18:52:23.382326", "\038\222\001\030\118\150\240\064" ; 19, 24, 50, 519, 30, "19:24:50.519030", "\186\102\242\077\040\016\241\064" ; 6, 2, 5, 661, 640, "06:02:05.661640", "\110\076\079\088\106\055\213\064" ; 8, 30, 19, 681, 293, "08:30:19.681293", "\128\244\077\154\235\230\221\064" ; 12, 51, 26, 107, 454, "12:51:26.107454", "\251\094\067\112\195\153\230\064" ; 21, 4, 5, 743, 633, "21:04:05.743633", "\116\183\235\229\091\132\242\064" ; 0, 20, 13, 167, 306, "00:20:13.167306", "\178\153\067\082\171\244\146\064" ; 4, 25, 55, 571, 335, "04:25:55.571335", "\008\090\129\033\201\041\207\064" ; 23, 44, 5, 9, 146, "23:44:05.009146", "\175\070\118\037\080\220\244\064" ; 10, 43, 13, 888, 632, "10:43:13.888632", "\070\096\172\111\060\216\226\064" ; 3, 6, 49, 791, 686, "03:06:49.791686", "\089\131\247\085\229\228\197\064" ; 0, 19, 49, 714, 52, "00:19:49.714052", "\147\142\114\048\219\150\146\064" ; 16, 55, 57, 749, 962, "16:55:57.749962", "\232\078\176\255\183\195\237\064" ; 15, 15, 47, 696, 954, "15:15:47.696954", "\155\121\114\077\118\212\234\064" ; 19, 52, 37, 308, 1, "19:52:37.308001", "\226\116\146\237\084\120\241\064" ; 15, 56, 20, 894, 99, "15:56:20.894099", "\140\129\117\156\156\004\236\064" ; 12, 0, 27, 165, 930, "12:00:27.165930", "\110\110\076\079\101\027\229\064" ; 3, 28, 20, 786, 578, "03:28:20.786578", "\224\128\150\174\100\106\200\064" ; 14, 8, 8, 31, 845, "14:08:08.031845", "\050\206\223\004\001\217\232\064" ; 22, 3, 37, 147, 288, "22:03:37.147288", "\113\169\074\091\146\099\243\064" ; 5, 39, 47, 726, 519, "05:39:47.726519", "\059\140\073\127\238\232\211\064" ; 7, 5, 35, 440, 459, "07:05:35.440459", "\014\242\122\048\220\239\216\064" ; 1, 58, 49, 48, 587, "01:58:49.048587", "\003\152\050\112\012\217\187\064" ; 18, 25, 49, 569, 995, "18:25:49.569995", "\190\019\179\030\217\050\240\064" ; 2, 49, 24, 906, 570, "02:49:24.906570", "\197\090\124\010\116\218\195\064" ; 7, 20, 18, 42, 532, "07:20:18.042532", "\066\035\216\184\130\204\217\064" ; 16, 45, 6, 911, 436, "16:45:06.911436", "\141\212\123\042\093\114\237\064" ; 18, 35, 14, 711, 541, "18:35:14.711541", "\204\208\120\098\043\086\240\064" ; 10, 57, 45, 452, 446, "10:57:45.452446", "\166\008\112\122\046\069\227\064" ; 8, 51, 22, 646, 494, "08:51:22.646494", "\196\094\040\096\169\034\223\064" ; 18, 52, 47, 559, 229, "18:52:47.559229", "\159\027\154\242\248\151\240\064" ; 10, 17, 42, 734, 884, "10:17:42.734884", "\075\115\043\132\215\024\226\064" ; 19, 22, 39, 771, 548, "19:22:39.771548", "\052\183\066\088\252\007\241\064" ; 10, 49, 33, 660, 528, "10:49:33.660528", "\195\157\011\035\181\007\227\064" ; 20, 4, 58, 302, 398, "20:04:58.302398", "\006\073\159\214\164\166\241\064" ; 3, 32, 46, 792, 62, "03:32:46.792062", "\051\161\073\098\101\239\200\064" ; 19, 58, 33, 415, 132, "19:58:33.415132", "\184\115\097\164\150\142\241\064" ; 16, 55, 19, 335, 995, "16:55:19.335995", "\020\150\120\192\234\190\237\064" ; 17, 21, 35, 157, 11, "17:21:35.157011", "\195\238\059\006\229\131\238\064" ; 21, 4, 23, 694, 826, "21:04:23.694826", "\039\222\001\030\123\133\242\064" ; 12, 45, 51, 186, 30, "12:45:51.186030", "\195\047\245\243\229\111\230\064" ; 4, 45, 2, 470, 216, "04:45:02.470216", "\132\217\004\024\158\179\208\064" ; 4, 29, 4, 829, 639, "04:29:04.829639", "\062\090\156\049\106\136\207\064" ; 9, 43, 52, 111, 845, "09:43:52.111845", "\039\247\059\148\003\027\225\064" ; 3, 53, 30, 322, 933, "03:53:30.322933", "\230\088\222\085\041\093\203\064" ; 0, 14, 12, 285, 563, "00:14:12.285563", "\149\015\065\213\072\162\138\064" ; 6, 14, 58, 12, 837, "06:14:58.012837", "\203\071\082\210\128\248\213\064" ; 14, 45, 11, 600, 888, "14:45:11.600888", "\146\120\121\058\243\238\233\064" ; 16, 59, 26, 235, 437, "16:59:26.235437", "\233\044\179\136\199\221\237\064" ; 19, 26, 30, 237, 468, "19:26:30.237468", "\221\062\171\204\099\022\241\064" ; 13, 29, 24, 209, 664, "13:29:24.209664", "\229\070\145\181\134\182\231\064" ; 17, 5, 52, 374, 89, "17:05:52.374089", "\154\126\137\248\011\014\238\064" ; 3, 50, 50, 425, 152, "03:50:50.425152", "\234\119\097\107\054\013\203\064" ; 16, 50, 23, 454, 709, "16:50:23.454709", "\134\227\249\140\238\153\237\064" ; 14, 29, 44, 728, 717, "14:29:44.728717", "\098\080\166\081\023\123\233\064" ; 21, 5, 54, 754, 829, "21:05:54.754829", "\209\146\199\019\044\139\242\064" ; 6, 46, 18, 489, 760, "06:46:18.489760", "\185\083\058\088\159\206\215\064" ; 18, 37, 53, 877, 740, "18:37:53.877740", "\038\025\057\011\030\096\240\064" ; 6, 29, 54, 259, 779, "06:29:54.259779", "\076\025\056\160\144\216\214\064" ; 0, 49, 25, 859, 522, "00:49:25.859522", "\098\128\068\019\184\043\167\064" ; 1, 52, 30, 83, 926, "01:52:30.083926", "\072\161\044\124\021\094\186\064" ; 4, 11, 6, 615, 244, "04:11:06.615244", "\136\189\080\192\078\109\205\064" ; 20, 50, 12, 190, 305, "20:50:12.190305", "\116\065\125\011\067\080\242\064" ; 15, 6, 22, 242, 823, "15:06:22.242823", "\119\189\052\197\199\141\234\064" ; 22, 40, 8, 533, 129, "22:40:08.533129", "\056\070\178\135\136\236\243\064" ; 4, 8, 34, 977, 215, "04:08:34.977215", "\021\145\097\021\125\033\205\064" ; 7, 52, 49, 477, 936, "07:52:49.477936", "\101\224\128\150\094\180\219\064" ; 1, 26, 10, 938, 252, "01:26:10.938252", "\104\119\072\049\240\050\180\064" ; 18, 12, 15, 850, 329, "18:12:15.850329", "\187\041\229\053\251\255\239\064" ; 4, 33, 54, 813, 707, "04:33:54.813707", "\097\134\198\019\180\012\208\064" ; 23, 41, 32, 120, 12, "23:41:32.120012", "\242\179\145\235\193\210\244\064" ; 8, 38, 24, 566, 451, "08:38:24.566451", "\242\177\187\064\036\096\222\064" ; 18, 9, 33, 487, 545, "18:09:33.487545", "\203\248\247\153\175\235\239\064" ; 22, 22, 11, 229, 994, "22:22:11.229994", "\069\048\014\174\051\169\243\064" ; 13, 26, 1, 725, 768, "13:26:01.725768", "\015\208\125\057\055\157\231\064" ; 5, 47, 4, 961, 685, "05:47:04.961685", "\003\062\063\140\061\086\212\064" ; 15, 0, 27, 217, 370, "15:00:27.217370", "\036\238\177\244\102\097\234\064" ; 6, 53, 21, 307, 590, "06:53:21.307590", "\165\247\141\175\083\056\216\064" ] let test () = let tests = Pa_ounit_lib.Runtime.collect (fun () -> let module T = Core.Stable.Unit_test (struct include Core.Stable.Ofday.V1 let equal x1 x2 = Time.Span.(abs (Time.Ofday.diff x1 x2) < (of_ns 1.)) let tests = let create ~hr ~min ~sec ~ms ~us = Time.Ofday.create ~hr ~min ~sec ~ms ~us () in unit_tests ~create end) in ()) in OUnit.TestList (List.map tests ~f:(fun f -> OUnit.TestCase f)) core-113.00.00/test/ofday_unit_tests_v1.mli000066400000000000000000000003621256461075500204330ustar00rootroot00000000000000(* [test] includes both hand generated tests - a few cases which may be of special interest, e.g. the start and end of day - and auto-generated unit tests looking at 10,000 randomly picked times of day. *) val test : unit -> OUnit.test core-113.00.00/test/pMap_test.ml000066400000000000000000000064761256461075500162410ustar00rootroot00000000000000open OUnit;; open Core.Std module Map = Map.Poly let m1 = Map.of_alist_exn ["a",1; "b",2; "c",3; "d",4] let m2 = Map.of_alist_exn ["a",1; "c",-3; "d",4; "e",5] let test = "pMap" >::: [ "merge1" >:: (fun () -> let f ~key:_ = function | `Left _ | `Right _ -> None | `Both (x, y) -> Some (x+y) in "eq1" @? Map.equal (=) (Map.merge ~f m1 m2) (Map.of_alist_exn ["a",2;"c",0;"d",8;]); "eq2" @? Map.equal (=) (Map.merge ~f m2 m1) (Map.of_alist_exn ["a",2;"c",0;"d",8;]); ); "merge2" >:: (fun () -> let f ~key:_ = function | `Left x -> Some x | `Right _ -> None | `Both (x, y) -> Some (x+y) in "eq" @? Map.equal (=) (Map.merge ~f m1 m2) (Map.of_alist_exn ["a",2;"b",2;"c",0;"d",8;]) ); "merge3" >:: (fun () -> let f ~key:_ = function | `Left x | `Right x -> Some x | `Both (x, y) -> Some (x+y) in "eq1" @? Map.equal (=) (Map.merge ~f m1 m2) (Map.of_alist_exn ["a",2;"b",2;"c",0;"d",8;"e",5]); "eq2" @? Map.equal (=) (Map.merge ~f m2 m1) (Map.of_alist_exn ["a",2;"b",2;"c",0;"d",8;"e",5]) ); "merge3" >:: (fun () -> let f ~key:_ = function | `Left x | `Right x -> Some x | `Both (x, y) -> Some (x+y) in "eq1" @? Map.equal (=) (Map.merge ~f m1 Map.empty) m1; "eq2" @? Map.equal (=) (Map.merge ~f Map.empty m1) m1; ); "sexp" >:: (fun () -> let s = "((a 1) (b 2) (c 3) (d 4))" in let m1' = Map.t_of_sexp string_of_sexp int_of_sexp (Sexp.of_string s) in "of_sexp1" @? (Map.equal (=) m1' m1); let s_dup = "((a 1) (b 2) (a 3) (d 4))" in let s_dup = Sexp.of_string s_dup in try ignore (Map.t_of_sexp string_of_sexp int_of_sexp s_dup); assert false with _ -> () ); "of_alist" >:: (fun () -> let a = ["a",1;"b",2;"c",3;"d",4] in let m = match Map.of_alist a with `Ok x -> x | `Duplicate_key _ -> failwith "argh" in "1" @? (Map.find_exn m "a" = 1 && Map.find_exn m "d" = 4); let a_dup = ["a",1;"b",2;"c",3;"b",4; "e", 5] in "2" @? (match Map.of_alist a_dup with `Ok _ -> false | `Duplicate_key x -> x = "b"); "3" @? (Map.to_alist (Map.of_alist_exn a) = List.sort ~cmp:Poly.ascending a); (try ignore (Map.of_alist_exn a_dup); assert false with _ -> ()) ); "for_all/exists" >:: (fun () -> let m = Map.of_alist_exn ["a",1;"b",2;"c",3;"d",4] in "1" @? (Map.for_all ~f:(fun x -> x > 0) m); "2" @? (not (Map.for_all ~f:(fun x -> x % 2 = 0) m)); "3" @? (Map.exists ~f:(fun x -> x % 2 = 0) m); "4" @? (not (Map.exists ~f:(fun x -> x < 0) m)); "short circuit forall" @? ( let sum = ref 0 in ignore (Map.for_all m ~f:(fun x -> sum := !sum + x; x <> 1)); !sum = 1 ); "short circuit exists" @? ( let sum = ref 0 in ignore (Map.exists m ~f:(fun x -> sum := !sum + x; x = 1)); !sum = 1 ); ); ] core-113.00.00/test/pSet_test.ml000066400000000000000000000012461256461075500162450ustar00rootroot00000000000000open OUnit;; open Core.Std let s1 = Set.Poly.of_list ["a"; "b"; "c"; "d"] (*let m2 = Map.of_alist ["a",1; "c",-3; "d",4; "e",5]*) let test = "pSet" >::: [ "sexp" >:: (fun () -> let s = "(a b c d)" in let s1' = Set.Poly.t_of_sexp string_of_sexp (Sexp.of_string s) in "of_sexp1" @? (Set.equal s1' s1); let s_dup = "(a b a d)" in let s_dup = Sexp.of_string s_dup in assert_raises (Sexplib.Conv.Of_sexp_error ( Failure "Set.t_of_sexp: duplicate element in set", (sexp_of_string "a"))) (fun () -> Set.Poly.t_of_sexp string_of_sexp s_dup) ); ] core-113.00.00/test/parent_death_test.ml000066400000000000000000000012231256461075500177630ustar00rootroot00000000000000(* Test parent death notification *) open Core.Std open Sys open Linux_ext open OUnit let handle_signal s = if Signal.equal s Signal.hup then () else ( printf "Got unknown signal: %s\n%!" (Signal.to_string s); assert false ) let run () = Signal.handle Signal.hup handle_signal; match Unix.fork () with | `In_the_child -> pr_set_pdeathsig Signal.hup; if Unix.getppid_exn () = Pid.init then ignore (Signal.send Signal.kill (`Pid (Unix.getpid ()))); Unix.sleep 3 | `In_the_parent _ -> Unix.sleep 1 let test = "Parent_death_test" >::: [ "test" >:: (fun () -> "1" @? (try run (); true with _ -> false)); ] core-113.00.00/test/quickcheck_deprecated.ml000066400000000000000000000000541256461075500205610ustar00rootroot00000000000000include Core_extended.Quickcheck_deprecated core-113.00.00/test/test.ml000066400000000000000000000030661256461075500152540ustar00rootroot00000000000000open OUnit let rec flatten_list acc = function | [] -> acc | (TestCase _ as r)::rest -> flatten_list (r::acc) rest | (TestList l)::rest -> let acc = flatten_list acc l in flatten_list acc rest | (TestLabel (lbl,test))::rest -> flatten_list (TestLabel (lbl,flatten test)::acc) rest and flatten = function | TestCase _ as res -> res | TestLabel (s,test) -> TestLabel (s,flatten test) | TestList l -> TestList (List.rev (flatten_list [] l)) let all () = flatten (TestList [ Avltree_test.test; Bag_test.test; Bigbuffer_test.test; Bigstring_test.test; Binary_packing_test.test; Blang_test.test; Common_test.test; Comparable_test.test; Condition_test.test; Crc_test.test; Doubly_linked_test.test; Float_test.test; Fdeque_test.test; Hash_queue_test.test; Heap_test.test; Interval_test.test; Int_conversions_test.test; Hash_heap_test.test; Core_char_test.test; Core_int_test.test; Core_array_test.test; Core_filename_test.test; Core_map_test.test; Core_set_test.test; Core_queue_test.test; Core_string_test.test; Core_mutex_test.test; PMap_test.test; PSet_test.test; Time_test.test; Zone_test.test; Int_set_test.test; Core_unix_test.test; Union_find_test.test; Ofday_unit_tests_v1.test (); Validate_test.test; ]) core-113.00.00/test/test_runner.ml000066400000000000000000000020271256461075500166410ustar00rootroot00000000000000open Core.Std;; open OUnit;; let rec count acc = function | TestCase _ -> acc + 1 | TestLabel (_,test) -> count acc test | TestList l -> List.fold_left l ~f:count ~init:acc let count_pa_ounit = function | TestList l -> List.fold_left l ~f:(fun (pa_ounit,total) test -> match test with | TestLabel (s,tst) when String.is_suffix ~suffix:".ml" s -> let cnt = count 0 tst in (pa_ounit+cnt,total+cnt) | test -> pa_ounit,count total test) ~init:(0,0) | v -> 0,count 0 v let main () = let cnt_ounit = "-cnt", Arg.Unit (fun () -> let pa_ounit,total = count_pa_ounit (Test.all ()) in Printf.printf "converted: %i total: %i\n%!" pa_ounit total; exit 0 ), " Count how many of the tests were converted to pa_ounit (for \ informational purposes only)" in ignore (run_test_tt_main ~arg_specs:[cnt_ounit] (Test.all ()):OUnit.test_result list) let () = Exn.handle_uncaught ~exit:true main core-113.00.00/test/time_test.ml000066400000000000000000000441641256461075500162760ustar00rootroot00000000000000open Core.Std open OUnit;; module Date = Date module Ofday = Time.Ofday module Span = Time.Span let teq t1 t2 = if Sys.word_size = 64 then Float.iround ~dir:`Zero (Time.to_float t1 *. 1000.) = Float.iround ~dir:`Zero (Time.to_float t2 *. 1000.) else true (* milliseconds since 1970 too large for truncate *) let speq s1 s2 = round (Time.Span.to_ms s1) = round (Time.Span.to_ms s2) let convtest ?tol f1 f2 = let x = float (Random.int 1_000_000) /. 1000. in let tol = match tol with | None -> Float.robust_comparison_tolerance | Some pct -> x *. pct in Float.abs (f1 (f2 x) -. x) <= tol let mintime_str = "0000-01-01 00:00:00.000000" let maxtime_str = "3000-01-01 00:00:00.000000" let time_gen () = Time.of_float (Quickcheck_deprecated.fg ()) let reasonable_time time = (* between about 1970 and 2070 *) let time = Time.to_float time in time > 0. && time < 100. *. 52. *. 24. *. 60. *. 60. let similar_time time time' = let time = Time.to_float time in let time' = Time.to_float time' in Float.abs (time -. time') < 0.01 let test_list = ref [] let add name test = test_list := (name >:: test) :: !test_list let () = add "t" (fun () -> let s1 = "2005-05-25 12:46-4:00" in let s2 = "2005-05-25 12:46:15-4:00" in let s3 = "2005-05-25 12:46:15.232-4:00" in let s4 = "2005-05-25 12:46:15.232338-4:00" in let time1 = Time.of_string s1 in let time2 = Time.of_string s2 in let time3 = Time.of_string s3 in let time4 = Time.of_string s4 in let now1 = Time.now () in let now2 = Time.now () in "diff1" @? (Float.iround_exn ~dir:`Nearest (Time.Span.to_sec (Time.diff time2 time1)) = 15); "diff1'" @? (Float.iround_exn ~dir:`Nearest (Time.Span.to_ms (Time.diff time2 time1)) = 15 * 1000); "diff2" @? (Float.iround_exn ~dir:`Nearest (Time.Span.to_ms (Time.diff time3 time2)) = 232); "diff3" @? (Float.iround_exn ~dir:`Nearest (Time.Span.to_us (Time.diff time4 time3)) = 338); "ord" @? (now2 >= now1); "sexp1" @? (Time.t_of_sexp (Time.sexp_of_t time1) = time1); "sexp2" @? (Time.t_of_sexp (Time.sexp_of_t time2) = time2); "sexp3" @? (Time.t_of_sexp (Time.sexp_of_t time3) = time3); let zone = Time.Zone.find_exn "America/New_York" in let date, ofday = Time.to_date_ofday time3 ~zone in "date" @? (date = Date.of_string "2005-05-25"); "ofday" @? (Ofday.(=.) ofday (Time.Ofday.of_string "12:46:15.232")); "ofday1" @? (Time.Ofday.of_string "09:13" = Time.Ofday.of_string "0913"); "add1" @? teq (Time.add time1 (sec 15.)) time2; "add2" @? teq (Time.add time2 (Time.Span.of_ms 232.)) time3; ) let () = add "Ofday_string_conversion" (fun () -> (* We want to test a number of times during the day, but testing all possible times is too expensive. We also want the test to always be the same, so this uses a specific Random.State to generate a repeatable series of random times to test *) let rand_state = Random.State.make [| 1; 2; 3; 4; 5; 6; 7 |] in for _i = 0 to 100_000 do let secs = Random.State.int rand_state 86_400_000 in let ofday = Ofday.of_span_since_start_of_day (Time.Span.of_ms (float secs)) in let ofday_string = Ofday.to_string ofday in let ofday' = Ofday.of_string ofday_string in if Ofday.(<>.) ofday ofday' then failwithf "(%d seconds) %s (%.20f) <> Ofday.of_string %s (%.20f)" secs ofday_string (Ofday.to_float ofday) (Ofday.to_string ofday') (Ofday.to_float ofday') (); let ofday' = Ofday.of_string ofday_string in if Ofday.(<>.) ofday ofday' then failwithf "%s <> Ofday.of_string %s" ofday_string (Ofday.to_string ofday') (); done) let () = add "date" (fun () -> let zone = Time.Zone.local in let start = Time.of_date_ofday ~zone (Date.create_exn ~y:1999 ~m:Month.Jan ~d:1) Ofday.start_of_day in let day = Span.of_day 1. in for i = 0 to 100_000 do let date = Time.to_date ~zone (Time.add start (Time.Span.scale day (float i))) in let date_string = Date.to_string date in let date' = Date.of_string date_string in if Date.(<>) date date' then failwithf "%s <> Date.of_string %s" date_string (Date.to_string date') (); done) module Old_date_impl = struct let of_tm tm = Date.create_exn ~y:(tm.Unix.tm_year + 1900) ~m:(Month.of_int_exn (tm.Unix.tm_mon + 1)) ~d:tm.Unix.tm_mday ;; let to_tm t = { Unix. tm_sec = 0; tm_min = 0; tm_hour = 12; tm_mday = Date.day t; tm_mon = Month.to_int (Date.month t) - 1; tm_year = Date.year t - 1900; tm_wday = 0; tm_yday = 0; tm_isdst = false; } ;; let to_time_internal t = let tm_date = to_tm t in let time = fst (Unix.mktime tm_date) in Time.of_float time ;; let of_time_internal time = of_tm (Unix.localtime (Float.round ~dir:`Down (Time.to_float time))) let add_days t n = let time = to_time_internal t in of_time_internal (Time.add time (Span.of_day (Float.of_int n))) ;; let day_of_week t = let uday = to_tm t in let sec, _ = Unix.mktime uday in let unix_wday = (Unix.localtime sec).Unix.tm_wday in Day_of_week.of_int_exn unix_wday ;; let exhaustive_date_range = if Sys.c_int_size () < 64 then Date.create_exn ~y:1970 ~m:Month.Jan ~d:1, 365 * 68 else Date.create_exn ~y:1900 ~m:Month.Jan ~d:1, 365 * 100 let exhaustive_day_of_week_test () = let start_date, ndays = exhaustive_date_range in let rec loop n current_date = if n = ndays then true else begin let old_method = day_of_week current_date in let new_method = Date.day_of_week current_date in if Day_of_week.(=) new_method old_method then loop (n + 1) (Date.add_days current_date 1) else false end in loop 1 start_date ;; let exhaustive_add_days_test () = let start_date, ndays = exhaustive_date_range in let rec loop n current_date = if n = ndays then true else begin let old_method = add_days current_date 1 in let new_method = Date.add_days current_date 1 in if (Date.(=) old_method new_method) then loop (n + 1) new_method else false end in loop 1 start_date; ;; end let () = add "day_of_week" (fun () -> "exhaustive" @? Old_date_impl.exhaustive_day_of_week_test ()) let () = add "add_days" (fun () -> "one" @? (Date.add_days (Date.of_string "2008-11-02") 1 = Date.of_string "2008-11-03"); "two" @? (Date.add_days (Date.of_string "2008-11-02") 2 = Date.of_string "2008-11-04"); "leap" @? (Date.add_days (Date.of_string "2000-02-28") 1 = Date.of_string "2000-02-29"); "exhaustive" @? Old_date_impl.exhaustive_add_days_test () ) let () = add "add_months" (fun () -> "zero" @? (Date.add_months (Date.of_string "2009-02-28") 0 = Date.of_string "2009-02-28"); "one" @? (Date.add_months (Date.of_string "2009-01-30") 1 = Date.of_string "2009-02-28"); "two" @? (Date.add_months (Date.of_string "2009-01-30") 2 = Date.of_string "2009-03-30"); "december" @? (Date.add_months (Date.of_string "2009-02-28") 10 = Date.of_string "2009-12-28"); "neg" @? (Date.add_months (Date.of_string "2009-01-30") (-11) = Date.of_string "2008-02-29"); ) let () = add "add_weekdays" (fun () -> let test lbl d1 n d2 = lbl @? (Date.add_weekdays (Date.of_string d1) n = Date.of_string d2) in test "one" "2009-01-01" 1 "2009-01-02"; test "one_weekend" "2009-01-02" 1 "2009-01-05"; test "neg_one" "2009-01-02" (-1) "2009-01-01"; test "neg_one_weekend" "2009-01-05" (-1) "2009-01-02"; test "neg_two_weekend" "2009-01-06" (-2) "2009-01-02"; test "non_leap_weekend" "2009-02-27" 1 "2009-03-02"; test "leap_weekend" "2008-02-28" 2 "2008-03-03"; ) ;; let () = add "add_business_days" (fun () -> let test lbl d1 n d2 = let is_holiday d = List.mem (List.map [ "2009-01-01"; "2009-03-01"; "2009-03-02"; ] ~f:Date.of_string) d in let res = Date.add_business_days ~is_holiday (Date.of_string d1) n in lbl @? (res = Date.of_string d2) in test "one" "2009-01-01" 1 "2009-01-05"; test "one_weekend" "2009-01-02" 1 "2009-01-05"; test "neg_one" "2009-01-02" (-1) "2008-12-31"; test "neg_one_weekend" "2009-01-05" (-1) "2009-01-02"; test "neg_two_weekend" "2009-01-06" (-2) "2009-01-02"; test "non_leap_weekend" "2009-02-27" 1 "2009-03-03"; test "leap_weekend" "2008-02-28" 2 "2008-03-03"; ) ;; let () = add "span_scale" (fun () -> "ms" @? speq (Time.Span.scale (sec 10.) 0.001) (Time.Span.of_ms 10.); "min" @? speq (Time.Span.scale (sec 10.) 60.) (Time.Span.of_min 10.); "hr" @? speq (Time.Span.scale (sec 10.) (60. *. 60.)) (Time.Span.of_hr 10.); ); add "span_conv" (fun () -> for _i = 1 to 100 do "sec" @? convtest Time.Span.to_sec sec; "ms" @? convtest Time.Span.to_ms Span.of_ms; "min" @? convtest (fun x -> Time.Span.to_sec x /. 60.) Span.of_min; "hr" @? convtest (fun x -> Time.Span.to_sec x /. 60. /. 60.) Span.of_hr; "sexp" @? convtest ~tol:0.0001 (fun x -> Time.Span.to_sec (Time.Span.t_of_sexp x)) (fun x -> Span.sexp_of_t (sec x)); done ); add "date" (fun () -> let d = Date.create_exn ~y:2004 ~m:Month.Apr ~d:15 in "conv1" @? (Date.to_string d = "2004-04-15"); "conv2" @? (d = Date.of_string "2004-04-15"); "conv3" @? (d = Date.of_string "20040415"); "conv4" @? (d = Date.of_string "15APR2004"); "conv5" @? (d = Date.of_string "04/15/2004"); "conv6" @? (d = Date.of_string "2004/04/15"); "conv7" @? (d = Date.of_string "4/15/4"); ); add "norollover" (fun () -> let zone = Time.Zone.of_string "nyc" in let t1 = Time.of_localized_string ~zone "2005-05-25 12:46:59.900" in let t2 = Time.add t1 (Time.Span.of_ms 99.9) in (* within 1 mic *) "60secspr" @? ((Time.to_string_abs ~zone t2) = "2005-05-25 12:46:59.999900-04:00"); ); add "to_string,of_string" (fun () -> let check time = if reasonable_time time then begin let time' = Time.of_string (Time.to_string time) in if similar_time time time' then true else begin Printf.printf "\nbad time: %f\n%!" (Time.to_float time); exit 7; end; end else true in Quickcheck_deprecated.laws_exn "string" 100 time_gen check; ); add "to_string,of_string2" (fun () -> let zone = Time.Zone.find_exn "America/New_York" in let s = "2005-06-01 10:15:08.047123-04:00" in let t = Time.of_string s in "foo" @? (Time.to_string_abs t ~zone = s) ); add "to_string,of_string3" (fun () -> let zone = Time.Zone.find_exn "America/New_York" in let s = "2006-06-16 04:37:07.082945-04:00" in let t = Time.of_string s in "foo" @? (Time.to_string_abs t ~zone = s) ); add "of_string with leap second" (fun () -> let expected_time_at_leap_second = Time.of_date_ofday ~zone:Time.Zone.utc (Date.create_exn ~y:2015 ~m:Jul ~d:1) Time.Ofday.start_of_day in "foo" @? List.for_all ~f:(fun s -> Time.of_string s = expected_time_at_leap_second) [ "2015-06-30 23:59:60Z" ; "2015-06-30 23:59:60.500Z" ]); add "to_filename_string,of_filename_string" (fun () -> let zone = Time.Zone.local in let check time = if reasonable_time time then let time' = Time.of_filename_string ~zone (Time.to_filename_string time ~zone) in similar_time time time' else true in Quickcheck_deprecated.laws_exn "string" 100 time_gen check; ); add "to_filename_string,of_filename_string2" (fun () -> let zone = Time.Zone.local in let s = "2005-06-01_10-15-08.047983" in let t = Time.of_filename_string s ~zone in "foo" @? (Time.to_filename_string t ~zone = s) ); add "of_sexp,to_sexp" (fun () -> let check time = if reasonable_time time then let time' = Time.t_of_sexp (Time.sexp_of_t time) in similar_time time time' else true in Quickcheck_deprecated.laws_exn "sexp" 100 time_gen check; ); add "daylight_saving_time" (fun () -> let zone = Time.Zone.find_exn "America/New_York" in let s = "2006-04-02 23:00:00.000000-04:00" in let time = Time.of_string s in "dst" @? (Time.to_string_abs ~zone time = s) ); add "weird_date_in_time" (fun () -> let zone = Time.Zone.find_exn "America/New_York" in let t1 = Time.of_string "01 JAN 2008 10:37:22.551-05:00" in "rnse1" @? (Time.to_string_abs t1 ~zone = "2008-01-01 10:37:22.551000-05:00"); let t2 = Time.of_string "01 FEB 2008 17:38:44.031-05:00" in "rnse2" @? (Time.to_string_abs t2 ~zone = "2008-02-01 17:38:44.031000-05:00") ); add "ofday_small_diff" (fun () -> let same x y = Float.abs (x -. y) < sqrt Float.epsilon_float in let check (s1,s2,d) = let t1 = Time.Ofday.of_string s1 in let t2 = Time.Ofday.of_string s2 in same (Time.Span.to_sec (Time.Ofday.small_diff t1 t2)) d && same (Time.Span.to_sec (Time.Ofday.small_diff t2 t1)) (~-. d) in "foo" @? List.for_all ~f:check ["10:00:01.298", "14:59:55.000", 6.298; "08:59:54.000", "10:00:01.555", (-7.555); "12:48:55.787", "17:48:55.000", 0.787; ]); add "occurrence_right_side" (fun () -> let times = [ "00:00:00"; "00:00:01"; "09:00:00"; "11:59:59"; "12:00:00"; "12:00:01"; "18:30:30"; "23:59:59"; ] in let now = Time.now () in let now_f = Time.to_float now in let zone = Time.Zone.local in let utimes = Time.to_ofday ~zone now :: List.map times ~f:(Time.Ofday.of_string) in let after_times = List.map utimes ~f:(fun ut -> Time.occurrence `First_after_or_at now ~zone ~ofday:ut) in let before_times = List.map utimes ~f:(fun ut -> Time.occurrence `Last_before_or_at now ~zone ~ofday:ut) in "right-side-after" @? List.for_all after_times ~f:(fun t -> Time.to_float t >= now_f); "right-side-before" @? List.for_all before_times ~f:(fun t -> Time.to_float t <= now_f); ); add "occurrence_distance" (fun () -> let now = Time.of_string "2007-05-04 13:00:00.000" in let after_times = [ ("13:00:00.000", "2007-05-04 13:00:00.000"); ("13:00:00.001", "2007-05-04 13:00:00.001"); ("11:59:59.999", "2007-05-05 11:59:59.999"); ("00:00:00.000", "2007-05-05 00:00:00.000"); ("12:59:59.000", "2007-05-05 12:59:59.000"); ] in let before_times = [ ("13:00:00.000", "2007-05-04 13:00:00.000"); ("13:00:00.001", "2007-05-03 13:00:00.001"); ("11:59:59.999", "2007-05-04 11:59:59.999"); ("00:00:00.000", "2007-05-04 00:00:00.000"); ("12:59:59.000", "2007-05-04 12:59:59.000"); ] in List.iter after_times ~f:(fun (od_s,prediction_s) -> let od = Time.Ofday.of_string od_s in let prediction = Time.of_string prediction_s in let real = Time.occurrence `First_after_or_at now ~zone:Time.Zone.local ~ofday:od in ("right-distance - " ^ od_s ^ "," ^ prediction_s) @? if Time.Span.to_ms (Time.diff prediction real) = 0. then true else false ); List.iter before_times ~f:(fun (od_s,prediction_s) -> let od = Time.Ofday.of_string od_s in let prediction = Time.of_string prediction_s in let real = Time.occurrence `Last_before_or_at now ~zone:Time.Zone.local ~ofday:od in ("right-distance - " ^ od_s ^ "," ^ prediction_s) @? if Time.Span.to_ms (Time.diff prediction real) = 0. then true else false ) ); add "diff" (fun () -> let d1 = Date.create_exn ~y:2000 ~m:Month.Jan ~d:1 in let d2 = Date.create_exn ~y:2000 ~m:Month.Jan ~d:2 in let d3 = Date.create_exn ~y:2000 ~m:Month.Feb ~d:28 in let d4 = Date.create_exn ~y:2000 ~m:Month.Mar ~d:1 in "normal-diff" @? (Date.diff d2 d1 = 1); "leap-diff" @? (Date.diff d4 d3 = 2) ) ;; let roundtrip s = let t = Span.of_string s in ("string roundtrip " ^ s) @? Span.(=) t (Time.Span.of_string (Time.Span.to_string t)); ("span roundtrip " ^ s) @? String.(=) s (Time.Span.to_string (Time.Span.of_string s)) ;; exception Finished let () = let assert_raises f = try f (); raise Finished with | Finished -> assert false | _ -> () in let extensions = ["ms";"s";"m";"h"] in add "roundtrip span<->string" (fun () -> List.iter extensions ~f:(fun ext -> let t x = roundtrip (x ^ ext) in t "1"; t "5"; t "1.34"; ); let t x = roundtrip (x ^ "s") in t "59.9999"; t "59"; ); add "Span.of_string (nan)" (fun () -> assert_raises (fun () -> ignore (Time.Span.of_string "nans"))); add "Span.of_string (inf)" (fun () -> assert_raises (fun () -> ignore (Time.Span.of_string "infs"))); add "Span.of_string" (fun () -> let test string secs = ("sec " ^ string) @? (Time.Span.to_sec (Time.Span.of_string string) = secs) in test "1ms" 0.001; test "95ms" 0.095; test "1222ms" 1.222; test "1.222s" 1.222; test "0.5m" 30.; test "1m" 60.; test "1h" (60. *. 60.); ); add "Time.of_string_fix_proto" (fun () -> let test s t = ("fix proto time " ^ s) @? (Time.of_string_fix_proto `Utc s = t) in test "20080603-13:55:35.577" (Time.of_float (Int64.float_of_bits 4742872407195577745L))) ;; let test = "time" >::: !test_list core-113.00.00/test/union_find_test.ml000066400000000000000000000020351256461075500174570ustar00rootroot00000000000000open OUnit;; open Core.Std open Union_find let test = "union_find" >::: [ "all" >:: (fun () -> let t1 = create 13 in assert (get t1 = 13); set t1 15; assert (get t1 = 15); assert (same_class t1 t1); let t2 = create 17 in assert (not (same_class t1 t2)); union t1 t2; assert (same_class t1 t1); assert (same_class t1 t2); assert (same_class t2 t2); assert (get t1 = get t2); assert (get t1 = 15 || get t1 = 17); let t3 = create 19 in union t1 t3; let t4 = create 21 in assert (not (same_class t3 t4)); union t1 t4; assert (same_class t3 t4); ); "zzz" >:: (fun () -> let u1 = create () in let u2 = create () in let u3 = create () in let u4 = create () in union u1 u2; union u3 u4; union u2 u4; assert (same_class u1 u3); ); ] ;; core-113.00.00/test/validate_test.ml000066400000000000000000000066521256461075500171310ustar00rootroot00000000000000open Core.Std open OUnit module V = Validate let test = "validate" >::: [ "basic" >:: (fun () -> "bounds" @? ( let res = V.name_list "foo" [ V.name "ok" (Int.validate_bound ~min:(Incl 0) ~max:(Incl 100) 5); V.name "incl_lower" (Int.validate_bound ~min:(Incl 0) ~max:(Incl 100) (-1)); V.name "incl_lower" (Int.validate_bound ~min:(Incl 0) ~max:(Incl 100) (0)); V.name "incl_upper" (Int.validate_bound ~min:(Incl 0) ~max:(Incl 100) (101)); V.name "incl_upper" (Int.validate_bound ~min:(Incl 0) ~max:(Incl 100) (100)); V.name "excl_lower" (Int.validate_bound ~min:(Excl 0) ~max:(Excl 100) (0)); V.name "excl_lower" (Int.validate_bound ~min:(Excl 0) ~max:(Excl 100) (100)); V.name "excl_lower" (Int.validate_bound ~min:(Excl 0) ~max:(Excl 100) (1)); V.name "excl_lower" (Int.validate_bound ~min:(Excl 0) ~max:(Excl 100) (99)); ] in let expected = [ "(foo.incl_lower \"value -1 < bound 0\")" ; "(foo.incl_upper \"value 101 > bound 100\")" ; "(foo.excl_lower \"value 0 <= bound 0\")" ; "(foo.excl_lower \"value 100 >= bound 100\")" ] in List.sort ~cmp:Poly.ascending (V.errors res) = List.sort ~cmp:Poly.ascending expected; ); "inf/nan" @? ( let res = V.name_list "bar" [ V.name "ok" (Float.validate_bound ~min:(Incl 0.) ~max:(Incl 100.) 5.); V.name "nan" (Float.validate_bound ~min:(Incl 0.) ~max:(Incl 100.) Float.nan); V.name "inf" (Float.validate_bound ~min:(Incl 0.) ~max:(Incl 100.) Float.infinity); ] in let expected = [ "(bar.nan \"value is NaN\")" ; "(bar.inf \"value is infinite\")" ] in List.sort ~cmp:Poly.ascending (V.errors res) = List.sort ~cmp:Poly.ascending expected; ); "nesting" @? ( let res = V.name_list "nesting" [ V.name "ok" (Float.validate_bound ~min:(Incl 0.) ~max:(Incl 100.) 5.); V.name "top" (Float.validate_ordinary Float.nan); V.name_list "sub0" [ V.name "sub1" (Float.validate_ordinary Float.nan); V.name "sub2" (Float.validate_ordinary Float.nan); V.name_list "sub3" [ V.name "sub4" (Float.validate_ordinary Float.nan); V.name "sub5" (Float.validate_ordinary Float.nan); ]]] in let expected = [ "(nesting.top \"value is NaN\")" ; "(nesting.sub0.sub1 \"value is NaN\")" ; "(nesting.sub0.sub2 \"value is NaN\")" ; "(nesting.sub0.sub3.sub4 \"value is NaN\")" ; "(nesting.sub0.sub3.sub5 \"value is NaN\")" ] in List.sort ~cmp:Poly.ascending (V.errors res) = List.sort ~cmp:Poly.ascending expected; ); "empty" @? ( let res = V.name_list "" [ V.name "ok1" (Float.validate_bound ~min:(Incl 0.) ~max:(Incl 100.) 5.); V.name "ok2" (Float.validate_bound ~min:(Incl 0.) ~max:(Incl 100.) 6.); V.name_list "sub" [ V.name "ok3" (Float.validate_bound ~min:(Incl 0.) ~max:(Incl 100.) 22.); V.name "ok4" (Float.validate_bound ~min:(Incl 0.) ~max:(Incl 100.) 36.); ]] in let expected = [] in List.sort ~cmp:Poly.ascending (V.errors res) = List.sort ~cmp:Poly.ascending expected ); ) ] core-113.00.00/test/zone_test.ml000066400000000000000000000137431256461075500163120ustar00rootroot00000000000000open OUnit open Core.Std (* We don't test Feb 29th because generating proper leap year dates is trickier. Also, there are no time zone changes on leap dates. *) let month_limits = Map.Poly.of_alist_exn [ 1, 31; 2, 28; 3, 31; 4, 30; 5, 31; 6, 30; 7, 31; 8, 31; 9, 30; 10, 31; 11, 30; 12, 31 ] let random_time state = let year = 1970 + Random.State.int state 67 in let month = 1 + (Random.State.int state 12) in let day = 1 + (Random.State.int state (Map.find_exn month_limits month)) in let hour = Random.State.int state 12 + 8 in let min = Random.State.int state 60 in let sec = Random.State.int state 60 in let ms = Random.State.int state 1_000 in let mic = Random.State.int state 1_000 in (year,month,day,hour,min,sec,ms,mic) ;; let random_time_str state = let year,month,day,hour,min,sec,ms,_mic = random_time state in sprintf "%d-%.2d-%.2d %.2d:%.2d:%.2d.%.3d000" year month day hour min sec ms ;; let random_tm state = let (year,month,day,hour,min,sec,_,_) = random_time state in {Unix. tm_sec = sec; tm_min = min; tm_hour = hour; tm_mday = day; tm_mon = month; tm_year = year - 1900; tm_wday = 0; tm_yday = 0; tm_isdst = false; } let zone_tests = ref [] let add name test = zone_tests := (name >:: test) :: !zone_tests let add_random_string_round_trip_test state s1 = let pos_neg = if Random.State.bool state then "+" else "-" in let distance = Int.to_string (Random.State.int state 10 + 1) in let s2 = String.concat [s1; pos_neg; distance; ":00"] in let zone = Time.Zone.local in let s1 = let t = Time.of_string s1 in let epoch = Time.to_epoch t in let utc_epoch = Time.Zone.shift_epoch_time zone `UTC epoch in let f = Time.Span.of_sec (utc_epoch -. epoch) |! Time.Span.to_float |! Float.to_int in s1 ^ (if f = 0 then "Z" else Printf.sprintf "%+03d:00" (f / 3600)) in add ("roundtrip string " ^ s1) (fun () -> "s1" @? (s1 = (Time.to_string_abs (Time.of_string s1) ~zone)); "s2-time" @? ( let s2_time1 = Time.of_string s2 in let s2_time2 = Time.of_string (Time.to_string_abs s2_time1 ~zone) in Time.(=.) s2_time1 s2_time2) ) let add_random_string_round_trip_tests state = for _i = 1 to 100 do add_random_string_round_trip_test state (random_time_str state) done; ;; let add_roundtrip_conversion_test state (zone_name,(zone:Time.Zone.t)) = add ("roundtrip conversion " ^ zone_name) (fun () -> let tm = random_tm state in let unix_time = 1664476678.000 in let time = Time.of_float unix_time in let (zone_date, zone_ofday) = let date,ofday = Time.to_date_ofday ~zone:Time.Zone.local time in Time.convert ~from_tz:Time.Zone.local ~to_tz:zone date ofday in let round_trip_time = let round_date,round_ofday = Time.convert ~from_tz:zone ~to_tz:Time.Zone.local zone_date zone_ofday in Time.of_date_ofday ~zone:Time.Zone.local round_date round_ofday in "time" @? (if time = round_trip_time then true else begin failwith (String.concat [ sprintf "tm: %s\n" (Sexp.to_string_hum (Unix.sexp_of_tm tm)); sprintf "unix_time: %.20f\n" unix_time; sprintf "our_time: %.20f\n" (Time.to_float time); sprintf "date, ofday: %s, %s\n" (Date.to_string zone_date) (Time.Ofday.to_string zone_ofday); sprintf "round_trip: %.20f\n" (Time.to_float round_trip_time) ]) end)) module Localtime_test_data = struct type t = { zone_name : string; unix_time : float; localtime_date_string : string; localtime_ofday_string : string; our_date_string : string; our_ofday_string : string; } with sexp end let add_random_localtime_tests state = List.iter (Time.Zone.initialized_zones ()) ~f:(fun (zone_name, zone) -> add ("localtime " ^ zone_name) (fun () -> let tm = random_tm state in let tm = Unix.gmtime (Unix.timegm tm) in (* goes through the dance of setting the env variable, then calling localtime, then setting the TZ back. We call localtime on 1000. each time to reset the internal state of localtime, which matters when we convert indeterminate times. *) Unix.putenv ~key:"TZ" ~data:zone_name; ignore (Unix.localtime 1000.); let unix_time,_ = Unix.mktime tm in let localtime = Unix.localtime unix_time in let localtime_date_string = Unix.strftime localtime "%Y-%m-%d" in let localtime_ofday_string = Unix.strftime localtime "%H:%M:%S.000000" in Unix.unsetenv ("TZ"); ignore (Unix.localtime 1000.); let our_date,our_ofday = Time.to_date_ofday (Time.of_float unix_time) ~zone in let test_data = {Localtime_test_data. zone_name; unix_time; our_date_string = Date.to_string our_date; our_ofday_string = Time.Ofday.to_string our_ofday; localtime_date_string; localtime_ofday_string; } in "date" @? (if Localtime_test_data.( test_data.localtime_date_string = test_data.our_date_string) then true else failwith (Sexp.to_string (Localtime_test_data.sexp_of_t test_data))); "ofday" @? (if Localtime_test_data.( test_data.localtime_ofday_string = test_data.our_ofday_string) then true else failwith (Sexp.to_string (Localtime_test_data.sexp_of_t test_data))))) ;; let add_roundtrip_conversion_tests state = List.iter (Time.Zone.initialized_zones ()) ~f:(add_roundtrip_conversion_test state) ;; let add_randomized_tests () = let state = Random.State.make [| 1; 2; 3; 4 |] in add_random_string_round_trip_tests state; add_random_localtime_tests state; add_roundtrip_conversion_tests state ;; let () = add_randomized_tests (); ;; let test = "zone" >::: !zone_tests core-113.00.00/top/000077500000000000000000000000001256461075500135615ustar00rootroot00000000000000core-113.00.00/top/core_install_printers.ml000066400000000000000000000011371256461075500205210ustar00rootroot00000000000000open Core.Std let printers = Pretty_printer.all () let eval_string ?(print_outcome = false) ?(err_formatter = Format.err_formatter) str = let lexbuf = Lexing.from_string str in let phrase = !Toploop.parse_toplevel_phrase lexbuf in Toploop.execute_phrase print_outcome err_formatter phrase let rec install_printers = function | [] -> true | printer :: printers -> let cmd = Printf.sprintf "#install_printer %s;;" printer in eval_string cmd && install_printers printers let () = if not (install_printers printers) then Format.eprintf "Problem installing Core-printers@." core-113.00.00/top/core_top.mldylib000066400000000000000000000001521256461075500167470ustar00rootroot00000000000000# OASIS_START # DO NOT EDIT (digest: d4446f978f17aa1e337a53d165c34e8e) Core_install_printers # OASIS_STOP core-113.00.00/top/core_top.mllib000066400000000000000000000001521256461075500164120ustar00rootroot00000000000000# OASIS_START # DO NOT EDIT (digest: d4446f978f17aa1e337a53d165c34e8e) Core_install_printers # OASIS_STOP core-113.00.00/with_typerep/000077500000000000000000000000001256461075500155025ustar00rootroot00000000000000core-113.00.00/with_typerep/src/000077500000000000000000000000001256461075500162715ustar00rootroot00000000000000core-113.00.00/with_typerep/src/std.ml000066400000000000000000000246231256461075500174240ustar00rootroot00000000000000 open Typerep_experimental.Std include (Core.Std : module type of Core.Std with module Month := Core.Std.Month and module Date := Core.Std.Date and module Time := Core.Std.Time ) open Core.Std module Serializable_of_typestructable(T : Typestructable.S0) = struct type t = Tagged.t include (T : Typestructable.S0 with type t := T.t) module B = Binrep.Tagged.Make_binable(T) include B include Sexprep.Tagged.Make_sexpable(T) let binable_b = let module B' = struct type nonrec t = t include B end in (module B' : Binable.S with type t = t) let t_of_string = Binable.of_string binable_b let string_of_t = Binable.to_string binable_b let t_of_bigstring = Binable.of_bigstring binable_b let bigstring_of_t = Binable.to_bigstring binable_b end (* A type with [Binable] and [Sexpable]. *) module type With_bin_io_and_sexp = sig type t include Binable.S with type t := t include Sexpable.S with type t := t end module type With_typerep_and_typestruct = sig type t include Typerepable.S0 with type t := t include Typestructable.S0 with type t := t end module Extending_with_typerep_test : sig (* entry point of tests *) val run : ?skip_sexp_str:bool -> (module With_bin_io_and_sexp with type t = 'a) -> (module With_typerep_and_typestruct with type t = 'a) -> 'a list -> unit (* Checks that the [Binable] and [Sexpable] implementations generated from the typerep are equivalent with the auto-generated ones. *) val run_with_typerep : (module With_bin_io_and_sexp with type t = 'a) -> (module Typerepable.S0 with type t = 'a) -> 'a list -> unit (* Checks that the [Binable] and [Sexpable] implementations generated from the typestruct are equivalent with the auto-generated ones. *) val run_with_typestruct : skip_sexp_str:bool -> (module With_bin_io_and_sexp with type t = 'a) -> (module Typestructable.S0 with type t = 'a) -> 'a list -> unit end = struct let run_with_typerep (type a) camlp4 rep (items : a list) = (* Make the modules we need. *) let module R = (val rep : Typerepable.S0 with type t = a) in let module M = struct type t = a include Binrep.Make_binable(R) include Sexprep.Make_sexpable(R) end in let module P = (val camlp4 : With_bin_io_and_sexp with type t = a) in (* Project the modules to [Binable]. *) let binable_m = (module M : Binable.S with type t = a) in let binable_p = (module P : Binable.S with type t = a) in (* Check that the binary encodings are identical. *) List.iter items ~f:(fun item -> let bin_from_p = Binable.to_string binable_p item in let bin_from_m = try Binable.to_string binable_m item with e -> Printf.printf "exn while bin_io rep serializing (1) using %s\nbuffer:%S\n%s\n%!" (Sexp.to_string_hum (Type_struct.sexp_of_typerep R.typerep_of_t)) bin_from_p (Exn.to_string e); raise e in assert (String.equal bin_from_p bin_from_m); let str = bin_from_m in (* they are the same *) (* deserialize and reserialize again *) let item_p = Binable.of_string binable_p str in let item_m = try Binable.of_string binable_m str with e -> Printf.printf "exn while bin_io rep unserializing using %s\nbuffer:%S\n%s\n%!" (Sexp.to_string_hum (Type_struct.sexp_of_typerep R.typerep_of_t)) str (Exn.to_string e); raise e in let bin_from_p = Binable.to_string binable_p item_p in let bin_from_m = try Binable.to_string binable_m item_m with e -> Printf.printf "exn while bin_io rep serializing (2) using %s\nbuffer:%S\n%s\n%!" (Sexp.to_string_hum (Type_struct.sexp_of_typerep R.typerep_of_t)) bin_from_p (Exn.to_string e); raise e in (* and recheck *) assert (String.equal bin_from_p bin_from_m); (* inverting the values *) let bin_from_p = Binable.to_string binable_p item_m in let bin_from_m = try Binable.to_string binable_m item_p with e -> Printf.printf "exn while bin_io rep serializing (3) using %s\nbuffer:%S\n%s\n%!" (Sexp.to_string_hum (Type_struct.sexp_of_typerep R.typerep_of_t)) bin_from_p (Exn.to_string e); raise e in (* and recheck *) assert (String.equal bin_from_p bin_from_m); ); (* Check that the sexp encodings are identical. *) List.iter items ~f:(fun item -> let sexp_from_m = M.sexp_of_t item in let sexp_from_p = P.sexp_of_t item in assert (String.equal (Sexp.to_string sexp_from_m) (Sexp.to_string sexp_from_p)); (* deserialize and reserialize again *) let item_m = M.t_of_sexp sexp_from_p in let item_p = P.t_of_sexp sexp_from_m in let sexp_from_m = M.sexp_of_t item_m in let sexp_from_p = P.sexp_of_t item_p in (* and recheck *) assert (String.equal (Sexp.to_string sexp_from_m) (Sexp.to_string sexp_from_p)); ); ;; let run_with_typestruct (type a) ~skip_sexp_str camlp4 str (items : a list) = (* Make the modules we need. *) let module R = (val str : Typestructable.S0 with type t = a) in let module M = Serializable_of_typestructable(R) in let module P = (val camlp4 : With_bin_io_and_sexp with type t = a) in (* Project the modules to [Binable]. *) let binable_m = (module M : Binable.S with type t = M.t) in let binable_p = (module P : Binable.S with type t = a) in List.iter items ~f:(fun item -> let bin_from_p = Binable.to_string binable_p item in let item_m = try Binable.of_string binable_m bin_from_p with e -> Printf.printf "exn while bin_io struct unserializing using %s\nbuffer:%S\n%s\n%!" (Sexp.to_string_hum (Type_struct.sexp_of_t R.typestruct_of_t)) bin_from_p (Exn.to_string e); raise e in let bin_from_m = try Binable.to_string binable_m item_m with e -> Printf.printf "exn while bin_io struct serializing using %s\nbuffer:%S\n%s\n%!" (Sexp.to_string_hum (Type_struct.sexp_of_t R.typestruct_of_t)) bin_from_p (Exn.to_string e); raise e in assert (String.equal bin_from_p bin_from_m); if skip_sexp_str then () else begin let sexp_m = M.sexp_of_t item_m in try let item_p = P.t_of_sexp sexp_m in let bin_from_p2 = Binable.to_string binable_p item_p in assert (String.equal bin_from_p bin_from_p2) with | exn -> begin Printf.eprintf "exn: %s\n" (Exn.to_string exn); Printf.eprintf "M.sexp_of_t: %s\n" (Sexp.to_string_hum sexp_m); Printf.eprintf "P.sexp_of_t: %s\n" (Sexp.to_string_hum (P.sexp_of_t item)); Printf.eprintf "%!"; assert false end; end ); ;; let run (type a) ?(skip_sexp_str=false) camlp4 generic (items : a list) = let module G = (val generic : With_typerep_and_typestruct with type t = a) in let rep = (module G : Typerepable.S0 with type t = a) in let str = (module G : Typestructable.S0 with type t = a) in run_with_typerep camlp4 rep items; run_with_typestruct ~skip_sexp_str camlp4 str items; ;; end module Test = Extending_with_typerep_test module Month = struct include (Month : (module type of Month with module Stable := Month.Stable)) module Stable = struct module V1 = struct type t = Month.Stable.V1.t = | Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec with typerep(abstract) include (Month.Stable.V1 : (module type of Month.Stable.V1 with type t := t)) module T = struct type t = | Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec with typerep end include Typestructable.Of_typerepable(T) end let () = Customrep.register0 (module V1 : Customrep_intf.S0) end TEST_UNIT = let months = (* Nobody likes Oct. *) [ Month.Jan; Feb; Mar; Apr; May; Jun; Jul; Aug; Sep; Nov; Dec ] in Test.run (module Month.Stable.V1 : With_bin_io_and_sexp with type t = Month.Stable.V1.t) (module Stable.V1 : With_typerep_and_typestruct with type t = Month.Stable.V1.t) (* List.map ~f:Month.Stable.V1.of_current *) months; ;; end module Date = struct include (Date : (module type of Date with module Stable := Date.Stable)) module Stable = struct module V1 = struct type t = Date.Stable.V1.t with typerep(abstract) include (Date.Stable.V1 : (module type of Date.Stable.V1 with type t := t)) module T = struct type t = { y : int ; m : Month.Stable.V1.t ; d : int } with typerep end include Typestructable.Of_typerepable(T) end let () = Customrep.register0 (module V1 : Customrep_intf.S0) end TEST_UNIT = let dates = (List.map ~f:Date.of_string [ "1970-01-01"; "1990-07-15"; "1996-02-29"; "2012-08-14" ]) in Test.run ~skip_sexp_str:true (module Date.Stable.V1 : With_bin_io_and_sexp with type t = Date.Stable.V1.t) (module Stable.V1 : With_typerep_and_typestruct with type t = Date.Stable.V1.t) (* List.map ~f:Date.Stable.V1.of_current *) dates; ;; end module Time = struct include (Time : (module type of Time with module Stable := Time.Stable)) module Stable = struct module V1 = struct type t = Time.Stable.V1.t with typerep(abstract) include (Time.Stable.V1 : (module type of Time.Stable.V1 with type t := t)) module T = struct type t = float with typerep end include Typestructable.Of_typerepable(T) end let () = Customrep.register0 (module V1 : Customrep_intf.S0) end TEST_UNIT = let times = (List.map ~f:Time.of_string [ "2012-08-14 15:23:40" ]) in Test.run ~skip_sexp_str:true (module Time.Stable.V1 : With_bin_io_and_sexp with type t = Time.Stable.V1.t) (module Stable.V1 : With_typerep_and_typestruct with type t = Time.Stable.V1.t) (* List.map ~f:Time.Stable.V1.of_current *) times; ;; end core-113.00.00/with_typerep/src/std.mli000066400000000000000000000047551256461075500176010ustar00rootroot00000000000000open Typerep_experimental.Std (* adding with_typerep to some stable types *) include module type of Core.Std with module Month := Core.Std.Month and module Date := Core.Std.Date and module Time := Core.Std.Time module Month : sig include module type of Core.Std.Month with module Stable := Core.Std.Month.Stable module Stable : sig module V1 : sig include module type of Core.Std.Month.Stable.V1 include Typerepable.S0 with type t := t end end end module Date : sig include module type of Core.Std.Date with module Stable := Core.Std.Date.Stable module Stable : sig module V1 : sig include module type of Core.Std.Date.Stable.V1 include Typerepable.S0 with type t := t end end end module Time : sig include module type of Core.Std.Time with module Stable := Core.Std.Time.Stable module Stable : sig module V1 : sig include module type of Core.Std.Time.Stable.V1 include Typerepable.S0 with type t := t end end end (* additional functor *) module Serializable_of_typestructable(T : Typestructable.S0) : sig type t include Typestructable.S0 with type t := T.t include Binable.S with type t := t include Sexpable.S with type t := t val t_of_string : string -> t val string_of_t : t -> string val t_of_bigstring : Bigstring.t -> t val bigstring_of_t : t -> Bigstring.t end module type With_bin_io_and_sexp = sig type t include Binable.S with type t := t include Sexpable.S with type t := t end module type With_typerep_and_typestruct = sig type t include Typerepable.S0 with type t := t include Typestructable.S0 with type t := t end module Extending_with_typerep_test : sig (* entry point of tests *) val run : ?skip_sexp_str:bool -> (module With_bin_io_and_sexp with type t = 'a) -> (module With_typerep_and_typestruct with type t = 'a) -> 'a list -> unit (* Checks that the [Binable] and [Sexpable] implementations generated from the typerep are equivalent with the auto-generated ones. *) val run_with_typerep : (module With_bin_io_and_sexp with type t = 'a) -> (module Typerepable.S0 with type t = 'a) -> 'a list -> unit (* Checks that the [Binable] and [Sexpable] implementations generated from the typestruct are equivalent with the auto-generated ones. *) val run_with_typestruct : skip_sexp_str:bool -> (module With_bin_io_and_sexp with type t = 'a) -> (module Typestructable.S0 with type t = 'a) -> 'a list -> unit end