From 35a5153058eab322a63641633beb19b86c04be3b Mon Sep 17 00:00:00 2001 From: Alexander Holcomb Date: Sun, 21 Aug 2022 21:45:26 -0400 Subject: [PATCH] first commit --- .gitignore | 6 + BUILDING.md | 29 + Cargo.toml | 35 + LIBRARY.md | 49 + LICENSE | 202 ++ README.md | 94 + RUNNING.md | 242 ++ benches/big_sur_benchmark.rs | 85 + benches/high_sierra_benchmark.rs | 85 + benches/monterey_benchmark.rs | 84 + examples/Cargo.toml | 6 + examples/parse_tracev3/Cargo.toml | 12 + examples/parse_tracev3/src/main.rs | 75 + examples/unifiedlog_parser/Cargo.toml | 13 + examples/unifiedlog_parser/src/main.rs | 369 ++ examples/unifiedlog_parser_json/Cargo.toml | 12 + examples/unifiedlog_parser_json/src/main.rs | 330 ++ src/catalog.rs | 778 ++++ src/chunks/firehose/activity.rs | 326 ++ src/chunks/firehose/firehose_log.rs | 3537 +++++++++++++++++++ src/chunks/firehose/flags.rs | 209 ++ src/chunks/firehose/loss.rs | 60 + src/chunks/firehose/message.rs | 1071 ++++++ src/chunks/firehose/mod.rs | 15 + src/chunks/firehose/nonactivity.rs | 342 ++ src/chunks/firehose/signpost.rs | 350 ++ src/chunks/firehose/trace.rs | 162 + src/chunks/mod.rs | 11 + src/chunks/oversize.rs | 410 +++ src/chunks/simpledump.rs | 173 + src/chunks/statedump.rs | 1033 ++++++ src/chunkset.rs | 2465 +++++++++++++ src/dsc.rs | 325 ++ src/error.rs | 98 + src/header.rs | 255 ++ src/lib.rs | 46 + src/message.rs | 1441 ++++++++ src/parser.rs | 508 +++ src/preamble.rs | 68 + src/timesync.rs | 416 +++ src/unified_log.rs | 1314 +++++++ src/util.rs | 148 + src/uuidtext.rs | 164 + 43 files changed, 17453 insertions(+) create mode 100755 .gitignore create mode 100644 BUILDING.md create mode 100755 Cargo.toml create mode 100644 LIBRARY.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 RUNNING.md create mode 100644 benches/big_sur_benchmark.rs create mode 100644 benches/high_sierra_benchmark.rs create mode 100644 benches/monterey_benchmark.rs create mode 100644 examples/Cargo.toml create mode 100644 examples/parse_tracev3/Cargo.toml create mode 100644 examples/parse_tracev3/src/main.rs create mode 100644 examples/unifiedlog_parser/Cargo.toml create mode 100755 examples/unifiedlog_parser/src/main.rs create mode 100644 examples/unifiedlog_parser_json/Cargo.toml create mode 100644 examples/unifiedlog_parser_json/src/main.rs create mode 100755 src/catalog.rs create mode 100755 src/chunks/firehose/activity.rs create mode 100755 src/chunks/firehose/firehose_log.rs create mode 100644 src/chunks/firehose/flags.rs create mode 100755 src/chunks/firehose/loss.rs create mode 100644 src/chunks/firehose/message.rs create mode 100644 src/chunks/firehose/mod.rs create mode 100755 src/chunks/firehose/nonactivity.rs create mode 100755 src/chunks/firehose/signpost.rs create mode 100755 src/chunks/firehose/trace.rs create mode 100644 src/chunks/mod.rs create mode 100755 src/chunks/oversize.rs create mode 100755 src/chunks/simpledump.rs create mode 100755 src/chunks/statedump.rs create mode 100755 src/chunkset.rs create mode 100755 src/dsc.rs create mode 100755 src/error.rs create mode 100755 src/header.rs create mode 100755 src/lib.rs create mode 100755 src/message.rs create mode 100755 src/parser.rs create mode 100644 src/preamble.rs create mode 100755 src/timesync.rs create mode 100755 src/unified_log.rs create mode 100755 src/util.rs create mode 100755 src/uuidtext.rs diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..d5654fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*/target +/target +Cargo.lock +*.DS_Store +*.logarchive +tests.zip diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..2fd4c0d --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,29 @@ +# How to build +1. Download and install Rust from https://www.rust-lang.org/ + * Windows users will need Windows C++ build tools https://visualstudio.microsoft.com/visual-cpp-build-tools/ + * Select `Desktop development with C++` + * This is a Rust requirement for Windows +2. Git clone the repo +3. Navigate to cloned repo. +4. Execute `cargo build` to build debug library. `cargo build --release` to build release version + * Navigate to examples directory and run `cargo build --release` to build the example files + * `unifiedlog_parser` and `unifiedlog_parser_json` can parse a live macOS system if no arguements are presented. Both can also parse a `logarchive` if passed as an arguement + +# Running test suite +1. Follow steps above +2. Download `tests.zip` from Github releases +3. Copy/move `tests.zip` to clone repo +4. Decompress `tests.zip` +5. Execute `cargo test --release` to run tests + * You can also just use `cargo test` to run tests but it will be slower + + +# Running benchmarks +1. Download `tests.zip` from Github releases +2. Copy/move `tests.zip` to clone repo +3. Decompress `tests.zip` +4. Run `cargo bench` +or +4. Install criterion, `cargo install cargo-criterion` +5. Run `cargo criterion` + diff --git a/Cargo.toml b/Cargo.toml new file mode 100755 index 0000000..b1c4fd6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "macos-unifiedlogs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nom = "7.1.0" +serde_json = "1.0.79" +serde = {version="1.0.136", features = ["derive"]} +log = "0.4.14" +lz4_flex = "0.9.2" +byteorder = "1.4.3" +plist = "1.3.1" +regex = "1.5.5" +base64 = "0.13.0" + +[dev-dependencies] +simplelog = "0.12.0" +csv = "1.1.6" +chrono = "0.4.19" +criterion = "0.3.5" + +[[bench]] +name = "high_sierra_benchmark" +harness = false + +[[bench]] +name = "big_sur_benchmark" +harness = false + +[[bench]] +name = "monterey_benchmark" +harness = false \ No newline at end of file diff --git a/LIBRARY.md b/LIBRARY.md new file mode 100644 index 0000000..504179f --- /dev/null +++ b/LIBRARY.md @@ -0,0 +1,49 @@ +# Parsing the log data +There two (2) ways to parse log data using `macos-unifiedlogs` +1. Running on a live system +2. Providing a custom directory + +Once you have added the library to `Cargo.toml` five (5) functions are used to parse the log data. +## Live System +1. `collect_strings_system()` Returns a `Result, ParserError>` which is a vector structure containing UUID data +2. `collect_shared_strings_system()` Returns a `Result, ParserError>` which is a vector structure containing UUID cached data +3. `collect_timesync_system()` Returns a `Result, ParserError>` which is a vector structure containing timesync data + +The above three (3) functions should be called first and load the results in memory. This will allow for fast lookups when building the logs. The UUID, UUID cache, and timesync files are very small and should not be impactful on memory usage. + +After getting the UUID, UUID cache, and timesync data we need the full path to a `tracev3` file we want to parse to `parse_log()`. +1. `parse_log(&str)` Returns a `Result` which is a structure containing the parsed Unified Log data + +Now we have all data needed to construct the Unified Log entries. +Before building the logs, the caller will need to decide how to deal with log data that is stored in a different `tracev3` file. +Sometimes a `tracev3` will reference log data in another `tracev3` file, specifically the log data may reference `Oversize` data in different `tracev3` file. +The function to construct the Unified Log data `build_log()` can be leveraged to both construct the logs and help track which logs may have data in a different `tracev3` files +`build_log()` expects: `&UnifiedLogData, &[UUIDText], &[SharedCacheStrings], &[TimesyncBoot], bool` + +1. `build_log(&UnifiedLogData, &[UUIDText], &[SharedCacheStrings], &[TimesyncBoot], exclude_missing: bool)` Returns a `(Vec, UnifiedLogData)` + +Passing a `true` bool to `build_log()` will cause it to exclude all `UnifiedLogData` entries from `Vec`, if it fails to find the correct `Oversize` data in the provided `UnifiedLogData`. +By tracking the excluded data separately you can parse each `tracev3` files and collect any entries that failed to build. Once all `tracev3` files are parsed you take a Vector of excluded `UnifiedLogData` and call `build_log` one more time to build any logs that had `Oversize` data in another `tracev3` file. Since all `tracev3` files are now parsed we have all the `Oversize` data and should be able to find all log entries that had data in another file. +The example projects `unifiedlog_parser` and `unifiedlog_parse_json` both pass `true` to `build_log()` + +Passing `false` bool to `build_log()` will cause it include all `UnifiedLogData` entries in `Vec` EVEN IF IT FAILED to find `Oversize` data in the parsed `tracev3` file. Any log entries that reference a different `tracev3` file will have data labeled `` + +Once `build_log()` has constructed the Unified Log entries you should immediantly output or upload the returned `Vec` before parsing other `tracev3` files. Parsing all `tracev3` files and appending the results to single Vector will increase total memory usage extremely fast. +The example files `unifiedlog_parser` and `unifiedlog_parse_json` both output `Vec` to a file and discards the results before parsing the next `tracev3` file + +The example projects `unifiedlog_parser` and `unifiedlog_parse_json` both support parsing on a live system if run with no arguements. + +## Custom paths +Similar to `parse_log()` you can also provide custom paths for the UUID, UUID cache, and Timesync files: +1. `collect_shared_strings(&str)` Expects a path containing UUID Cache files (ex: `/private/var/db/uuidtext/dsc`) +2. `collect_timesync(&str)` Expects a path containing timesync files (ex: `/private/var/db/diagnostics/timesync`) +Both functions return the same values as `collect_shared_strings_system() and collect_timesync_system()` + +3. `collect_strings(&str)` Expects a path containing one (1) or more, two (2) character subdirectories that contain UUID files (ex: `/private/var/db/uuidtext`). Each subdirectory should contain the UUID file(s). This function returns the same value as `collect_strings_system()` + +Parsing the `tracev3` files then follows the same process as mentioned in parsing on a `Live System` + +The example projects `unifiedlog_parser` and `unifiedlog_parse_json` both support parsing custom paths that follow the same structure as a `logarchive` +``` +./unifiedlog_parser system.logarchive/ +``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b6c0701 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + 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 2022 Mandiant, Inc. + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..58c034f --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# macos-unifiedlogs +A simple Rust library that can help parse the macOS Unified Log files. + +Unified Logs were introduced in macOS version 10.12 (Sierra, 2016). Part of Apple's goal to create a unified log format for all Apple products. They exist on macOS, iOS, watchOS, tvOS. +The Unified Logs replace many of the old log formats Apple used. This simple library can be used to parse files. +Data that is currently extracted includes: +* Process ID +* Thread ID +* Activity ID +* Log Message +* Timestamp (Intel and ARM supported) +* Effective User ID (EUID) +* Log Type +* Event Type +* Library +* Subsystem +* Category +* Process +* Raw message - Message extracted from UUID file +* Message entries - Message parts from tracev3 file. Combines with Raw message to get the Log Message +* Library UUID +* Process UUID +* Boot UUID +* Timezone + +## Running +Three (3) simple example binaries are available in `examples`. +* `unifiedlog_parser` - Can parse all logs into a single CSV file. It can also be run on a live system. The resulting CSV file will likely be quite large +* `unifiedlog_parser_json` - Can parse all logs into JSON files. It can also be run on a live system. Each log file (tracev3 file) will correspond to a single JSON file. Depending on the logs, hundreds of JSON files may get created +* `parse_tracev3` - Can parse a single tracev3 file without any timesync or uuidtext files, to a JSON file. However, without the uuidtext or timesync files the resulting JSON file will be heavily incomplete. + +See `RUNNING.md` for overview of running the example binaries +## Using as Library +If you want to import this project into a Rust application add the following to you `Cargo.toml` file +``` +macos-unifiedlogs = {git = "https://github.com/mandiant/macos-UnifiedLogs"} +``` +If you want to pin to a specific commit +``` +macos-unifiedlogs = {git = "https://github.com/mandiant/macos-UnifiedLogs", rev = "commit hash"} +``` +See `Library.md` for overview of how to use the library. Simple example projects are also available to review and use +## Status +This library has been heavily tested on log data from macOS Sierra (10.12.5) to Monterey (12). +Its been tested against 100+ million log entries. However, due the complexity of the Unified Log format there are some limitations: +1. No printf style error code lookup support. This library does not do any error code lookups for log messages. The native `log` command on macOS supports error code lookups when it encounters printf style `%m` messages. + An example base log messsage: 'Failed to open file, error: %m' + a. This Library outputs: + ``` + Failed to open file, error: 1 + ``` + b. The macOS Log command outputs: + ``` + Failed to open file, error: no such file or directory + ``` + Here the error code 1 gets translated to the error string message + +2. No support for custom object decoders. The Unified Log format allows a developer to log abrirtary data to the logs. Apple also includes a handful of custom objects that developer can use to log raw data. An example list can be found in `man os_log`. However, it is not a complete list. +``` +man os_log +... + To format a log message, use a printf(3) format string. You may also use the "%@" format specifier for use with Obj-C/CF/Swift objects, and %.*P which can be used to decode arbitrary binary data. The logging system also supports custom decoding of values by denoting value types inline in the format %{value_type}d. The built-in value type decoders are: + + Value type Custom specifier Example output + BOOL %{BOOL}d YES + bool %{bool}d true + darwin.errno %{darwin.errno}d [32: Broken pipe] + darwin.mode %{darwin.mode}d drwxr-xr-x + darwin.signal %{darwin.signal}d [sigsegv: Segmentation Fault] + time_t %{time_t}d 2016-01-12 19:41:37 + timeval %{timeval}.*P 2016-01-12 19:41:37.774236 + timespec %{timespec}.*P 2016-01-12 19:41:37.2382382823 + bytes %{bytes}d 4.72 kB + iec-bytes %{iec-bytes}d 4.61 KiB + bitrate %{bitrate}d 123 kbps + iec-bitrate %{iec-bitrate}d 118 Kibps + uuid_t %{uuid_t}.16P 10742E39-0657-41F8-AB99-878C5EC2DCAA + sockaddr %{network:sockaddr}.*P fe80::f:86ff:fee9:5c16 + in_addr %{network:in_addr}d 127.0.0.1 + in6_addr %{network:in6_addr}.16P fe80::f:86ff:fee9:5c16 +``` +Currently when the library encounters log messages that contain arbitrary binary data, it will base64 the data as a string. +Support for custom decoders will hopefully be added in version 2 of the library. + +3. No support for log messages that have custom object structures or protocol buffer data. + Some logs contain binary plist files, custom object structures, or protocol buffer data. This library currently supports parsing binary plist data, but it does not support custom object structures, or protocol buffer data. + The custom object structures are similar to the custom decoders mentioned above. But there is no list of decoders + Support for custom object structures will hopefully be added in version 2 of the library + +# References +https://github.com/ydkhatri/UnifiedLogReader +https://github.com/libyal/dtformats/blob/main/documentation/Apple%20Unified%20Logging%20and%20Activity%20Tracing%20formats.asciidoc +https://eclecticlight.co/2018/03/19/macos-unified-log-1-why-what-and-how/ +https://www.crowdstrike.com/blog/how-to-leverage-apple-unified-log-for-incident-response/ diff --git a/RUNNING.md b/RUNNING.md new file mode 100644 index 0000000..d078087 --- /dev/null +++ b/RUNNING.md @@ -0,0 +1,242 @@ +# Example binaries +Precompiled binaries are available in GitHub releases, they can also be built following the steps under `BUILDING.md`. +`unifiedlog_parser` and `unifiedlog_parser_json` can run on a live macOS system or a `logarchive`. To run on a live system execute `unifiedlog_parser` or `unifiedlog_parser_json` with no arguements. +To run on a `logarchive` provide the full path to the `logarchive` as an arguement to `unifiedlog_parser` or `unifiedlog_parser_json`. +- Ex: `unifiedlog_parser ` + +To create an `logarchive`, execute `sudo log collect`. If you cannot execute the `log` command, you can manually create a `logarchive`. +`parse_tracev3` can parse a single `tracev3`. +- Ex: `parse_tracev3 ` + +## Manually create logarchive +1. Create a directory. Ex: `mkdir output` +2. Copy all contents from `/private/var/db/uuidtext` to created directory +3. Copy all contents from `/private/var/db/diagnostics` to created directory +4. Execute `unifiedlog_parser` or `unifiedlog_parser_json` with path to created directory +- Ex: `unifiedlog_parser ` + +# Possible Issues when running +Due to the complexity and size of the Unified Logs, some warnings may be encountered when running `unifiedlog_parser` or the other example binaries. Any errors or crashes should be reported. +Example of running `unifiedlog_parser` on a live system +``` +./unifiedlog_parser +Starting Unified Log parser... +Parsing: /var/db/diagnostics/Persist/00000000000005c8.tracev3 +21:55:02 [WARN] Failed to get message string from alternative UUIDText file: "8151CEAA69AF3C059474AAE3403C91A7" +Parsing: /var/db/diagnostics/Persist/00000000000005b8.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a7.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005b1.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005c1.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005ba.tracev3 +Parsing: /var/db/diagnostics/Persist/000000000000059e.tracev3 +21:56:46 [WARN] Failed to get message string from alternative UUIDText file: "9C2D765DAEE334BFA507FDC05EFA7019" +Parsing: /var/db/diagnostics/Persist/00000000000005c0.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005b0.tracev3 +21:57:44 [WARN] Failed to get message string from alternative UUIDText file: "8151CEAA69AF3C059474AAE3403C91A7" +21:57:44 [WARN] Failed to get message string from alternative UUIDText file: "8151CEAA69AF3C059474AAE3403C91A7" +21:57:44 [WARN] Failed to get message string from alternative UUIDText file: "8151CEAA69AF3C059474AAE3403C91A7" +Parsing: /var/db/diagnostics/Persist/000000000000059d.tracev3 +21:57:50 [WARN] Failed to get message string from alternative UUIDText file: "9C2D765DAEE334BFA507FDC05EFA7019" +21:57:50 [WARN] Failed to get message string from alternative UUIDText file: "9C2D765DAEE334BFA507FDC05EFA7019" +Parsing: /var/db/diagnostics/Persist/00000000000005b9.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005c9.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005af.tracev3 +21:58:53 [WARN] Failed to get message string from alternative UUIDText file: "8151CEAA69AF3C059474AAE3403C91A7" +Parsing: /var/db/diagnostics/Persist/00000000000005a6.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005b2.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005c2.tracev3 +Parsing: /var/db/diagnostics/Persist/000000000000059f.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005bb.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005ad.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a4.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005ae.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a5.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005c3.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005b3.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005bc.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a9.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005bf.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005b6.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005c6.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a0.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a1.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005aa.tracev3 +Parsing: /var/db/diagnostics/Persist/000000000000059c.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a8.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005c7.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005b7.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a3.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005ac.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005be.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005b5.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005c5.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005bd.tracev3 +22:07:02 [WARN] Failed to get message string from alternative UUIDText file: "8151CEAA69AF3C059474AAE3403C91A7" +Parsing: /var/db/diagnostics/Persist/00000000000005c4.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005b4.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005a2.tracev3 +Parsing: /var/db/diagnostics/Persist/00000000000005ab.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000167.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000166.tracev3 +22:08:12 [WARN] Failed to get string: Utf8Error { valid_up_to: 0, error_len: Some(1) } +22:08:12 [WARN] Failed to get string: Utf8Error { valid_up_to: 0, error_len: None } +22:08:12 [WARN] Failed to get string: Utf8Error { valid_up_to: 2, error_len: Some(1) } +Parsing: /var/db/diagnostics/Special/000000000000016f.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000174.tracev3 +Parsing: /var/db/diagnostics/Special/000000000000016d.tracev3 +22:08:20 [WARN] Failed to get string: Utf8Error { valid_up_to: 2, error_len: Some(1) } +Parsing: /var/db/diagnostics/Special/000000000000016e.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000170.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000169.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000168.tracev3 +Parsing: /var/db/diagnostics/Special/000000000000016a.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000171.tracev3 +22:08:33 [WARN] Failed to get string: Utf8Error { valid_up_to: 2, error_len: Some(1) } +Parsing: /var/db/diagnostics/Special/000000000000016c.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000173.tracev3 +22:08:38 [WARN] Failed to get string: Utf8Error { valid_up_to: 2, error_len: Some(1) } +Parsing: /var/db/diagnostics/Special/000000000000016b.tracev3 +Parsing: /var/db/diagnostics/Special/0000000000000172.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000baf.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb9.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc9.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b79.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba6.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc0.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb0.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be2.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd2.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b84.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b94.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b8d.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b9d.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000beb.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bdb.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb1.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc1.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b95.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b85.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd3.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be3.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b7a.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bdc.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bec.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b9e.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b8e.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bba.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bca.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc8.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb8.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba7.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b78.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b7c.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be1.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd1.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b87.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b97.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc3.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb3.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bcc.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bbc.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bea.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bda.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd8.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be8.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bae.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba5.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bad.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be9.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd9.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba4.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b7b.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b96.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b86.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd0.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be0.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb2.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc2.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bbb.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bcb.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b9f.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b8f.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bee.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bde.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b8c.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b9c.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba8.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b83.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b93.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be5.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd5.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc7.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb7.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba1.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bf3.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000baa.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba0.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bf2.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bbf.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bcf.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba9.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b9b.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b8b.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bdd.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bed.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd4.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be4.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b92.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b82.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b7f.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb6.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc6.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bf0.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba2.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b99.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b89.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bab.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bef.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bdf.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bcd.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bbd.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc4.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb4.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b7d.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b80.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b90.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be6.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd6.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b9a.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b8a.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bbe.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bce.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bb5.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bc5.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b7e.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bd7.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000be7.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b91.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b81.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bf1.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000ba3.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000bac.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b88.tracev3 +Parsing: /var/db/diagnostics/Signpost/0000000000000b98.tracev3 + +Finished parsing Unified Log data. Saved results to: output.csv +``` + +* Breakdown of warnings + * `[WARN] Failed to get message string from alternative UUIDText file: "8151CEAA69AF3C059474AAE3403C91A7"` + * The parser failed to extract the base log message string from the designated UUIDText file (UUID file). + macOS `log` command would report the error as `error: ~~> Invalid image <8151CEAA-69AF-3C05-9474-AAE3403C91A7>` + * `[WARN] Failed to get string: Utf8Error { valid_up_to: 0, error_len: Some(1) }` + * The parser failed to extract string metadata from a log message. This is commonly happens with log files in the `Special` directory. The parser currently attempts to extract strings associated with metdata on the log entry. Sometimes the metadata cannot be represented as a string + +`` in output. Sometimes log data may get deleted or not recorded, if the parser fails to find all the data associated with the log entries it will use `` when attempting to build the logs. +macOS `log` command would report the missing data as `` +This sometimes occurs when a `tracev3` file references data in a deleted `tracev3` file. + +## Reviewing Unified Logs +The logs typically retain 30 days worth of information. +Some possible starting points when reviewing log data: +https://github.com/jamf/jamfprotect/tree/main/unified_log_filters diff --git a/benches/big_sur_benchmark.rs b/benches/big_sur_benchmark.rs new file mode 100644 index 0000000..63f80e7 --- /dev/null +++ b/benches/big_sur_benchmark.rs @@ -0,0 +1,85 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use std::path::PathBuf; + +use criterion::{criterion_group, criterion_main, Criterion}; +use macos_unifiedlogs::{ + dsc::SharedCacheStrings, + parser::{build_log, collect_shared_strings, collect_strings, collect_timesync, parse_log}, + timesync::TimesyncBoot, + unified_log::UnifiedLogData, + uuidtext::UUIDText, +}; + +fn big_sur_parse_log(path: &str) { + let _ = parse_log(&path).unwrap(); +} + +fn bench_build_log( + log_data: &UnifiedLogData, + string_results: &Vec, + shared_strings_results: &Vec, + timesync_data: &Vec, + exclude_missing: bool, +) { + let (_, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); +} + +fn big_sur_single_log_benchpress(c: &mut Criterion) { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path + .push("tests/test_data/system_logs_big_sur.logarchive/Persist/0000000000000004.tracev3"); + + c.bench_function("Benching Parsing One Big Sur Log", |b| { + b.iter(|| big_sur_parse_log(&test_path.display().to_string())) + }); +} + +fn big_sur_build_log_benchbress(c: &mut Criterion) { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000004.tracev3"); + let exclude_missing = false; + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + c.bench_function("Benching Building One Big Sur Log", |b| { + b.iter(|| { + bench_build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ) + }) + }); +} + +criterion_group!( + benches, + big_sur_single_log_benchpress, + big_sur_build_log_benchbress +); +criterion_main!(benches); diff --git a/benches/high_sierra_benchmark.rs b/benches/high_sierra_benchmark.rs new file mode 100644 index 0000000..c91a43b --- /dev/null +++ b/benches/high_sierra_benchmark.rs @@ -0,0 +1,85 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use std::path::PathBuf; + +use criterion::{criterion_group, criterion_main, Criterion}; +use macos_unifiedlogs::{ + dsc::SharedCacheStrings, + parser::{build_log, collect_shared_strings, collect_strings, collect_timesync, parse_log}, + timesync::TimesyncBoot, + unified_log::UnifiedLogData, + uuidtext::UUIDText, +}; +fn high_sierra_parse_log(path: &str) { + let _ = parse_log(&path).unwrap(); +} + +fn bench_build_log( + log_data: &UnifiedLogData, + string_results: &Vec, + shared_strings_results: &Vec, + timesync_data: &Vec, + exclude_missing: bool, +) { + let (_, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); +} + +fn high_sierra_single_log_benchpress(c: &mut Criterion) { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push( + "tests/test_data/system_logs_high_sierra.logarchive/Persist/0000000000000002.tracev3", + ); + + c.bench_function("Benching Parsing One High Sierra Log", |b| { + b.iter(|| high_sierra_parse_log(&test_path.display().to_string())) + }); +} + +fn high_sierra_build_log_benchbress(c: &mut Criterion) { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_high_sierra.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000002.tracev3"); + let exclude_missing = false; + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + c.bench_function("Benching Building One High Sierra Log", |b| { + b.iter(|| { + bench_build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ) + }) + }); +} + +criterion_group!( + benches, + high_sierra_single_log_benchpress, + high_sierra_build_log_benchbress +); +criterion_main!(benches); diff --git a/benches/monterey_benchmark.rs b/benches/monterey_benchmark.rs new file mode 100644 index 0000000..954ffa0 --- /dev/null +++ b/benches/monterey_benchmark.rs @@ -0,0 +1,84 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use std::path::PathBuf; + +use criterion::{criterion_group, criterion_main, Criterion}; +use macos_unifiedlogs::{ + dsc::SharedCacheStrings, + parser::{build_log, collect_shared_strings, collect_strings, collect_timesync, parse_log}, + timesync::TimesyncBoot, + unified_log::UnifiedLogData, + uuidtext::UUIDText, +}; +fn monterey_parse_log(path: &str) { + let _ = parse_log(&path).unwrap(); +} + +fn bench_build_log( + log_data: &UnifiedLogData, + string_results: &Vec, + shared_strings_results: &Vec, + timesync_data: &Vec, + exclude_missing: bool, +) { + let (_, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); +} + +fn monterey_single_log_benchpress(c: &mut Criterion) { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path + .push("tests/test_data/system_logs_monterey.logarchive/Persist/0000000000000004.tracev3"); + + c.bench_function("Benching Parsing One Monterey Log", |b| { + b.iter(|| monterey_parse_log(&test_path.display().to_string())) + }); +} + +fn monterey_build_log_benchbress(c: &mut Criterion) { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_monterey.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000004.tracev3"); + let exclude_missing = false; + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + c.bench_function("Benching Building One Monterey Log", |b| { + b.iter(|| { + bench_build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ) + }) + }); +} + +criterion_group!( + benches, + monterey_single_log_benchpress, + monterey_build_log_benchbress +); +criterion_main!(benches); diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 0000000..2eb5d2b --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] +members = [ + "unifiedlog_parser", + "unifiedlog_parser_json", + "parse_tracev3", +] \ No newline at end of file diff --git a/examples/parse_tracev3/Cargo.toml b/examples/parse_tracev3/Cargo.toml new file mode 100644 index 0000000..574191e --- /dev/null +++ b/examples/parse_tracev3/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "parse_tracev3" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +simplelog = "0.12.0" +serde_json = "1.0.79" +log = "0.4.14" +macos-unifiedlogs = {path = "../../"} \ No newline at end of file diff --git a/examples/parse_tracev3/src/main.rs b/examples/parse_tracev3/src/main.rs new file mode 100644 index 0000000..350f99e --- /dev/null +++ b/examples/parse_tracev3/src/main.rs @@ -0,0 +1,75 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::LevelFilter; +use macos_unifiedlogs::dsc::SharedCacheStrings; +use macos_unifiedlogs::parser::{build_log, parse_log}; +use macos_unifiedlogs::timesync::TimesyncBoot; +use macos_unifiedlogs::unified_log::LogData; +use macos_unifiedlogs::uuidtext::UUIDText; + +use simplelog::{Config, SimpleLogger}; +use std::env; +use std::error::Error; +use std::fs::OpenOptions; +use std::io::Write; +use std::path::Path; + +fn main() { + println!("Starting Unified Log parser..."); + // Set logging to Error only, since we are parsing only a tracev3, we wont have enough data to build the whole log + SimpleLogger::init(LevelFilter::Error, Config::default()) + .expect("Failed to initialize simple logger"); + + let args: Vec = env::args().collect(); + if args.len() == 2 { + let archive_path = &args[1]; + parse_trace_file(archive_path); + } else { + println!("Expected an argument for a tracev3 file") + } +} + +// Parse single tracev3 file +fn parse_trace_file(path: &str) { + let log_data = parse_log(path).unwrap(); + let filename = Path::new(path); + // Pass empty UUID, UUID cache, timesync files + let string_results: Vec = Vec::new(); + let shared_strings_results: Vec = Vec::new(); + let timesync_data: Vec = Vec::new(); + let exclude_missing = false; + + // We only get minimal data since we dont have the log metadata + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + output(&results, filename.file_name().unwrap().to_str().unwrap()).unwrap(); + println!( + "\nParsed file: {} to {}.json", + path, + filename.file_name().unwrap().to_str().unwrap() + ) +} + +// Create JSON file +fn output(results: &Vec, output_name: &str) -> Result<(), Box> { + let mut json_file = OpenOptions::new() + .append(true) + .create(true) + .open(format!("{}.json", output_name))?; + + let serde_data = serde_json::to_string(&results)?; + + json_file.write_all(serde_data.as_bytes())?; + + Ok(()) +} diff --git a/examples/unifiedlog_parser/Cargo.toml b/examples/unifiedlog_parser/Cargo.toml new file mode 100644 index 0000000..2a087d7 --- /dev/null +++ b/examples/unifiedlog_parser/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "unifiedlog_parser" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +simplelog = "0.12.0" +csv = "1.1.6" +chrono = "0.4.19" +log = "0.4.14" +macos-unifiedlogs = {path = "../../"} \ No newline at end of file diff --git a/examples/unifiedlog_parser/src/main.rs b/examples/unifiedlog_parser/src/main.rs new file mode 100755 index 0000000..47cbd5a --- /dev/null +++ b/examples/unifiedlog_parser/src/main.rs @@ -0,0 +1,369 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use chrono::{SecondsFormat, TimeZone, Utc}; +use log::LevelFilter; +use macos_unifiedlogs::dsc::SharedCacheStrings; +use macos_unifiedlogs::parser::{ + build_log, collect_shared_strings, collect_shared_strings_system, collect_strings, + collect_strings_system, collect_timesync, collect_timesync_system, parse_log, +}; +use macos_unifiedlogs::timesync::TimesyncBoot; +use macos_unifiedlogs::unified_log::{LogData, UnifiedLogData}; +use macos_unifiedlogs::uuidtext::UUIDText; +use simplelog::{Config, SimpleLogger}; +use std::error::Error; +use std::fs::OpenOptions; +use std::path::PathBuf; +use std::{env, fs}; + +fn main() { + println!("Starting Unified Log parser..."); + // Set logging level to warning + SimpleLogger::init(LevelFilter::Warn, Config::default()) + .expect("Failed to initialize simple logger"); + + let args: Vec = env::args().collect(); + // Create headers for CSV file + output_header().unwrap(); + + // If arguement is passed, parsing logarchive + if args.len() == 2 { + let archive_path = &args[1]; + parse_log_archive(archive_path); + } else { + parse_live_system(); + } +} + +// Parse a provided directory path. Currently expect the path to follow macOS log collect structure +fn parse_log_archive(path: &str) { + let mut archive_path = PathBuf::from(path); + + // Parse all UUID files which contain strings and other metadata + let string_results = collect_strings(&archive_path.display().to_string()).unwrap(); + + archive_path.push("dsc"); + // Parse UUID cache files which also contain strings and other metadata + let shared_strings_results = + collect_shared_strings(&archive_path.display().to_string()).unwrap(); + archive_path.pop(); + + archive_path.push("timesync"); + // Parse all timesync files + let timesync_data = collect_timesync(&archive_path.display().to_string()).unwrap(); + archive_path.pop(); + + // Keep UUID, UUID cache, timesync files in memory while we parse all tracev3 files + // Allows for faster lookups + parse_trace_file( + &string_results, + &shared_strings_results, + ×ync_data, + path, + ); + + println!("\nFinished parsing Unified Log data. Saved results to: output.csv"); +} + +// Parse a live macOS system +fn parse_live_system() { + let strings = collect_strings_system().unwrap(); + let shared_strings = collect_shared_strings_system().unwrap(); + let timesync_data = collect_timesync_system().unwrap(); + + parse_trace_file( + &strings, + &shared_strings, + ×ync_data, + "/private/var/db/diagnostics", + ); + + println!("\nFinished parsing Unified Log data. Saved results to: output.csv"); +} + +// Use the provided strings, shared strings, timesync data to parse the Unified Log data at provided path. +// Currently expect the path to follow macOS log collect structure +fn parse_trace_file( + string_results: &[UUIDText], + shared_strings_results: &[SharedCacheStrings], + timesync_data: &[TimesyncBoot], + path: &str, +) { + // We need to persist the Oversize log entries (they contain large strings that don't fit in normal log entries) + // Some log entries have Oversize strings located in different tracev3 files. + // This is very rare. Seen in ~20 log entries out of ~700,000. Seen in ~700 out of ~18 million + let mut oversize_strings = UnifiedLogData { + header: Vec::new(), + catalog_data: Vec::new(), + oversize: Vec::new(), + }; + + // Exclude missing data from returned output. Keep separate until we parse all oversize entries. + // Then at end, go through all missing data and check all parsed oversize entries again + let mut exclude_missing = true; + let mut missing_data: Vec = Vec::new(); + + let mut archive_path = PathBuf::from(path); + archive_path.push("Persist"); + + let mut log_count = 0; + if archive_path.exists() { + let paths = fs::read_dir(&archive_path).unwrap(); + + // Loop through all tracev3 files in Persist directory + for log_path in paths { + let data = log_path.unwrap(); + let full_path = data.path().display().to_string(); + println!("Parsing: {}", full_path); + + let log_data = if data.path().exists() { + parse_log(&full_path).unwrap() + } else { + println!("File {} no longer on disk", full_path); + continue; + }; + + // Get all constructed logs and any log data that failed to get constrcuted (exclude_missing = true) + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + // Track Oversize entries + oversize_strings + .oversize + .append(&mut log_data.oversize.to_owned()); + + // Track missing logs + missing_data.push(missing_logs); + log_count += results.len(); + output(&results).unwrap(); + } + } + + archive_path.pop(); + archive_path.push("Special"); + + if archive_path.exists() { + let paths = fs::read_dir(&archive_path).unwrap(); + + // Loop through all tracev3 files in Special directory + for log_path in paths { + let data = log_path.unwrap(); + let full_path = data.path().display().to_string(); + println!("Parsing: {}", full_path); + + let mut log_data = if data.path().exists() { + parse_log(&full_path).unwrap() + } else { + println!("File {} no longer on disk", full_path); + continue; + }; + + // Append our old Oversize entries in case these logs point to other Oversize entries the previous tracev3 files + log_data.oversize.append(&mut oversize_strings.oversize); + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + // Track Oversize entries + oversize_strings.oversize = log_data.oversize; + // Track missing logs + missing_data.push(missing_logs); + log_count += results.len(); + + output(&results).unwrap(); + } + } + + archive_path.pop(); + archive_path.push("Signpost"); + + if archive_path.exists() { + let paths = fs::read_dir(&archive_path).unwrap(); + + // Loop through all tracev3 files in Signpost directory + for log_path in paths { + let data = log_path.unwrap(); + let full_path = data.path().display().to_string(); + println!("Parsing: {}", full_path); + + let log_data = if data.path().exists() { + parse_log(&full_path).unwrap() + } else { + println!("File {} no longer on disk", full_path); + continue; + }; + + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + + // Signposts have not been seen with Oversize entries + missing_data.push(missing_logs); + log_count += results.len(); + + output(&results).unwrap(); + } + } + archive_path.pop(); + archive_path.push("HighVolume"); + + if archive_path.exists() { + let paths = fs::read_dir(&archive_path).unwrap(); + + // Loop through all tracev3 files in HighVolume directory + for log_path in paths { + let data = log_path.unwrap(); + let full_path = data.path().display().to_string(); + println!("Parsing: {}", full_path); + + let log_data = if data.path().exists() { + parse_log(&full_path).unwrap() + } else { + println!("File {} no longer on disk", full_path); + continue; + }; + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + + // Oversize entries have not been seen in logs in HighVolume + missing_data.push(missing_logs); + log_count += results.len(); + + output(&results).unwrap(); + } + } + archive_path.pop(); + + archive_path.push("logdata.LiveData.tracev3"); + + // Check if livedata exists. We only have it if 'log collect' was used + if archive_path.exists() { + println!("Parsing: logdata.LiveData.tracev3"); + let mut log_data = parse_log(&archive_path.display().to_string()).unwrap(); + log_data.oversize.append(&mut oversize_strings.oversize); + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + // Track missing data + missing_data.push(missing_logs); + log_count += results.len(); + + output(&results).unwrap(); + // Track oversize entries + oversize_strings.oversize = log_data.oversize; + archive_path.pop(); + } + + exclude_missing = false; + + // Since we have all Oversize entries now. Go through any log entries that we were not able to build before + for mut leftover_data in missing_data { + // Add all of our previous oversize data to logs for lookups + leftover_data + .oversize + .append(&mut oversize_strings.oversize.to_owned()); + + // Exclude_missing = false + // If we fail to find any missing data its probably due to the logs rolling + // Ex: tracev3A rolls, tracev3B references Oversize entry in tracev3A will trigger missing data since tracev3A is gone + let (results, _) = build_log( + &leftover_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + log_count += results.len(); + + output(&results).unwrap(); + } + println!("Parsed {} log entries", log_count); +} + +// Create csv file and create headers +fn output_header() -> Result<(), Box> { + let csv_file = OpenOptions::new() + .append(true) + .create(true) + .open("output.csv")?; + let mut writer = csv::Writer::from_writer(csv_file); + + writer.write_record(&[ + "Timestamp", + "Event Type", + "Log Type", + "Subsystem", + "Thread ID", + "PID", + "EUID", + "Library", + "Library UUID", + "Activity ID", + "Category", + "Process", + "Process UUID", + "Message", + "Raw Message", + "Boot UUID", + "System Timezone Name", + ])?; + Ok(()) +} + +// Append or create csv file +fn output(results: &Vec) -> Result<(), Box> { + let csv_file = OpenOptions::new() + .append(true) + .create(true) + .open("output.csv")?; + let mut writer = csv::Writer::from_writer(csv_file); + + for data in results { + let date_time = Utc.timestamp_nanos(data.time as i64); + writer.write_record(&[ + date_time.to_rfc3339_opts(SecondsFormat::Millis, true), + data.event_type.to_owned(), + data.log_type.to_owned(), + data.subsystem.to_owned(), + data.thread_id.to_string(), + data.pid.to_string(), + data.euid.to_string(), + data.library.to_owned(), + data.library_uuid.to_owned(), + data.activity_id.to_string(), + data.category.to_owned(), + data.process.to_owned(), + data.process_uuid.to_owned(), + data.message.to_owned(), + data.raw_message.to_owned(), + data.boot_uuid.to_owned(), + data.timezone_name.to_owned(), + ])?; + } + Ok(()) +} diff --git a/examples/unifiedlog_parser_json/Cargo.toml b/examples/unifiedlog_parser_json/Cargo.toml new file mode 100644 index 0000000..789956a --- /dev/null +++ b/examples/unifiedlog_parser_json/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "unifiedlog_parser_json" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +simplelog = "0.12.0" +serde_json = "1.0.79" +log = "0.4.14" +macos-unifiedlogs = {path = "../../"} \ No newline at end of file diff --git a/examples/unifiedlog_parser_json/src/main.rs b/examples/unifiedlog_parser_json/src/main.rs new file mode 100644 index 0000000..3f63765 --- /dev/null +++ b/examples/unifiedlog_parser_json/src/main.rs @@ -0,0 +1,330 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::LevelFilter; +use macos_unifiedlogs::dsc::SharedCacheStrings; +use macos_unifiedlogs::parser::{ + build_log, collect_shared_strings, collect_shared_strings_system, collect_strings, + collect_strings_system, collect_timesync, collect_timesync_system, parse_log, +}; +use macos_unifiedlogs::timesync::TimesyncBoot; +use macos_unifiedlogs::unified_log::{LogData, UnifiedLogData}; +use macos_unifiedlogs::uuidtext::UUIDText; +use simplelog::{Config, SimpleLogger}; +use std::error::Error; +use std::fs::OpenOptions; +use std::io::Write; +use std::path::PathBuf; +use std::{env, fs}; + +fn main() { + println!("Starting Unified Log parser..."); + // Set logging level to warning + SimpleLogger::init(LevelFilter::Warn, Config::default()) + .expect("Failed to initialize simple logger"); + + let args: Vec = env::args().collect(); + // If arguement is passed, parsing logarchive + if args.len() == 2 { + let archive_path = &args[1]; + parse_log_archive(archive_path); + } else { + parse_live_system(); + } +} + +// Parse a provided directory path. Currently expect the path to follow macOS log collect structure +fn parse_log_archive(path: &str) { + let mut archive_path = PathBuf::from(path); + + // Parse all UUID files which contain strings and other metadata + let string_results = collect_strings(&archive_path.display().to_string()).unwrap(); + + archive_path.push("dsc"); + // Parse UUID cache files which also contain strings and other metadata + let shared_strings_results = + collect_shared_strings(&archive_path.display().to_string()).unwrap(); + archive_path.pop(); + + archive_path.push("timesync"); + // Parse all timesync files + let timesync_data = collect_timesync(&archive_path.display().to_string()).unwrap(); + archive_path.pop(); + + // Keep UUID, UUID cache, timesync files in memory while we parse all tracev3 files + // Allows for faster lookups + parse_trace_file( + &string_results, + &shared_strings_results, + ×ync_data, + path, + ); + + println!("\nFinished parsing Unified Log data. Saved results to json files"); +} + +// Parse a live macOS system +fn parse_live_system() { + let strings = collect_strings_system().unwrap(); + let shared_strings = collect_shared_strings_system().unwrap(); + let timesync_data = collect_timesync_system().unwrap(); + + parse_trace_file( + &strings, + &shared_strings, + ×ync_data, + "/private/var/db/diagnostics", + ); + + println!("\nFinished parsing Unified Log data. Saved results to json files"); +} + +// Use the provided strings, shared strings, timesync data to parse the Unified Log data at provided path. +// Currently expect the path to follow macOS log collect structure +fn parse_trace_file( + string_results: &[UUIDText], + shared_strings_results: &[SharedCacheStrings], + timesync_data: &[TimesyncBoot], + path: &str, +) { + // We need to persist the Oversize log entries (they contain large strings that don't fit in normal log entries) + // Some log entries have Oversize strings located in different tracev3 files. + // This is very rare. Seen in ~20 log entries out of ~700,000. Seen in ~700 out of ~18 million + let mut oversize_strings = UnifiedLogData { + header: Vec::new(), + catalog_data: Vec::new(), + oversize: Vec::new(), + }; + + // Exclude missing data from returned output. Keep separate until we parse all oversize entries. + // Then at end, go through all missing data and check all parsed oversize entries again + let mut exclude_missing = true; + let mut missing_data: Vec = Vec::new(); + + let mut archive_path = PathBuf::from(path); + archive_path.push("Persist"); + + let mut log_count = 0; + if archive_path.exists() { + let paths = fs::read_dir(&archive_path).unwrap(); + + // Loop through all tracev3 files in Persist directory + for log_path in paths { + let data = log_path.unwrap(); + let full_path = data.path().display().to_string(); + println!("Parsing: {}", full_path); + + let log_data = if data.path().exists() { + parse_log(&full_path).unwrap() + } else { + println!("File {} no longer on disk", full_path); + continue; + }; + + // Get all constructed logs and any log data that failed to get constrcuted (exclude_missing = true) + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + // Take all Oversize entries and add to tracker + oversize_strings + .oversize + .append(&mut log_data.oversize.clone()); + + // Add log entries that failed to find strings to missing tracker + // We will try parsing them again at the end once we have all Oversize entries + missing_data.push(missing_logs); + log_count += results.len(); + output( + &results, + &format!("persist_{}", data.file_name().to_str().unwrap()), + ) + .unwrap(); + } + } + + archive_path.pop(); + archive_path.push("Special"); + + if archive_path.exists() { + let paths = fs::read_dir(&archive_path).unwrap(); + + // Loop through all tracev3 files in Special directory + for log_path in paths { + let data = log_path.unwrap(); + let full_path = data.path().display().to_string(); + println!("Parsing: {}", full_path); + + let mut log_data = if data.path().exists() { + parse_log(&full_path).unwrap() + } else { + println!("File {} no longer on disk", full_path); + continue; + }; + // Append all previously parsed Oversize entries from tracker to current parsed tracev3 file + log_data.oversize.append(&mut oversize_strings.oversize); + + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + // Take all Oversize entries and add to tracker + oversize_strings.oversize = log_data.oversize; + + // Add log entries that failed to find strings to missing tracker + // We will try parsing them again at the end once we have all Oversize entries + missing_data.push(missing_logs); + log_count += results.len(); + + output( + &results, + &format!("special_{}", data.file_name().to_str().unwrap()), + ) + .unwrap(); + } + } + + archive_path.pop(); + archive_path.push("Signpost"); + + if archive_path.exists() { + let paths = fs::read_dir(&archive_path).unwrap(); + + // Loop through all tracev3 files in Signpost directory + for log_path in paths { + let data = log_path.unwrap(); + let full_path = data.path().display().to_string(); + println!("Parsing: {}", full_path); + + let log_data = if data.path().exists() { + parse_log(&full_path).unwrap() + } else { + println!("File {} no longer on disk", full_path); + continue; + }; + + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + + // Signposts have not been seen with Oversize entries + missing_data.push(missing_logs); + log_count += results.len(); + + output( + &results, + &format!("signpost_{}", data.file_name().to_str().unwrap()), + ) + .unwrap(); + } + } + archive_path.pop(); + archive_path.push("HighVolume"); + + if archive_path.exists() { + let paths = fs::read_dir(&archive_path).unwrap(); + + // Loop through all tracev3 files in HighVolume directory + for log_path in paths { + let data = log_path.unwrap(); + let full_path = data.path().display().to_string(); + let log_data = if data.path().exists() { + parse_log(&full_path).unwrap() + } else { + println!("File {} no longer on disk", full_path); + continue; + }; + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + + // Oversize entries have not been seen in logs in HighVolume + missing_data.push(missing_logs); + log_count += results.len(); + + output( + &results, + &format!("highvolume_{}", data.file_name().to_str().unwrap()), + ) + .unwrap(); + } + } + archive_path.pop(); + + archive_path.push("logdata.LiveData.tracev3"); + + // Check if livedata exists. We only have it if 'log collect' was used + if archive_path.exists() { + let mut log_data = parse_log(&archive_path.display().to_string()).unwrap(); + log_data.oversize.append(&mut oversize_strings.oversize); + let (results, missing_logs) = build_log( + &log_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + missing_data.push(missing_logs); + log_count += results.len(); + + output(&results, "liveData").unwrap(); + oversize_strings.oversize = log_data.oversize; + archive_path.pop(); + } + + // Include all log entries now, if any logs are missing data its because the data has rolled + exclude_missing = false; + for mut leftover_data in missing_data { + // Add all of our previous oversize data to logs for lookups + leftover_data + .oversize + .append(&mut oversize_strings.oversize.clone()); + + // Exclude_missing = false + // If we fail to find any missing data its probably due to the logs rolling + // Ex: tracev3A rolls, tracev3B references Oversize entry in tracev3A will trigger missing data since tracev3A is gone + let (results, _) = build_log( + &leftover_data, + string_results, + shared_strings_results, + timesync_data, + exclude_missing, + ); + log_count += results.len(); + + output(&results, "dataFoundInMultipleLogFiles").unwrap(); + } + println!("Parsed {} log entries", log_count); +} + +// Create JSON files +fn output(results: &Vec, output_name: &str) -> Result<(), Box> { + let mut json_file = OpenOptions::new() + .append(true) + .create(true) + .open(format!("{}.json", output_name))?; + + let serde_data = serde_json::to_string(&results)?; + + json_file.write_all(serde_data.as_bytes())?; + + Ok(()) +} diff --git a/src/catalog.rs b/src/catalog.rs new file mode 100755 index 0000000..361ca76 --- /dev/null +++ b/src/catalog.rs @@ -0,0 +1,778 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use byteorder::{LittleEndian, ReadBytesExt}; +use log::{error, warn}; +use nom::Needed; +use nom::{ + bytes::complete::take, + number::complete::{be_u128, le_u16, le_u32, le_u64}, +}; +use std::mem::size_of; + +use crate::{ + error::CatalogProcessUUIDEntryError, + util::{extract_string, padding_size}, +}; + +#[derive(Debug, Clone)] +pub struct CatalogChunk { + pub chunk_tag: u32, + pub chunk_sub_tag: u32, + pub chunk_data_size: u64, + pub catalog_subsystem_strings_offset: u16, // offset relative to start of catalog UUIDs + pub catalog_process_info_entries_offset: u16, // offset relative to start of catalog UUIDs + pub number_process_information_entries: u16, + pub catalog_offset_sub_chunks: u16, // offset relative to start of catalog UUIDs + pub number_sub_chunks: u16, + pub unknown: Vec, // unknown 6 bytes, padding? alignment? + pub earliest_firehose_timestamp: u64, + pub catalog_uuids: Vec, // array of UUIDs in big endian + pub catalog_subsystem_strings: Vec, // array of strings with end-of-string character + pub catalog_process_info_entries: Vec, + pub catalog_subchunks: Vec, +} + +#[derive(Debug, Clone)] +pub struct ProcessInfoEntry { + pub index: u16, + pub unknown: u16, // flags? + pub catalog_main_uuid_index: u16, + pub catalog_dsc_uuid_index: u16, + pub first_number_proc_id: u64, + pub second_number_proc_id: u32, + pub pid: u32, + pub effective_user_id: u32, // euid + pub unknown2: u32, + pub number_uuids_entries: u32, + pub unknown3: u32, + pub uuid_info_entries: Vec, // Catalog process information UUID information entry + pub number_subsystems: u32, + pub unknown4: u32, + pub subsystem_entries: Vec, // Catalog process information sub system + pub main_uuid: String, // main UUID from catalog_uuids. Points to UUIDinfo file that contains strings + pub dsc_uuid: String, // dsc UUID from catalog_uuids. Points to dsc shared string file that contains strings +} + +// Part of ProcessInfoEntry +#[derive(Debug, Clone)] +pub struct ProcessUUIDEntry { + pub size: u32, + pub unknown: u32, + pub catalog_uuid_index: u16, + pub load_address: u64, + pub uuid: String, +} + +// Part of ProcessInfoEntry +#[derive(Debug, Clone)] +pub struct ProcessInfoSubsystem { + pub identifer: u16, + pub subsystem_offset: u16, // Represents the offset to the subsystem from the start of the subsystem entries + pub category_offset: u16, // Represents the offset to the subsystem category from the start of the subsystem entries +} + +// Part of CatalogChunk, possible 64-bit alignment padding at end +#[derive(Debug, Clone)] +pub struct CatalogSubchunk { + pub start: u64, + pub end: u64, + pub uncompressed_size: u32, + pub compression_algorithm: u32, // Should always be LZ4 (value 0x100) + pub number_index: u32, + pub indexes: Vec, // indexes size = number_index * u16 + pub number_string_offsets: u32, + pub string_offsets: Vec, // string_offsets size = number_string_offsets * u16 +} + +#[derive(Debug)] +pub struct SubsystemInfo { + pub subsystem: String, + pub category: String, +} + +impl CatalogChunk { + /// Parse log Catalog data. The log Catalog contains metadata related to log entries such as Process info, Subsystem info, and the compressed log entries + pub fn parse_catalog(data: &[u8]) -> nom::IResult<&[u8], CatalogChunk> { + let mut catalog_chunk = CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }; + + // Parse initial part Catalog chunk based on known sizes + let (input, chunk_tag) = take(size_of::())(data)?; + let (input, chunk_sub_tag) = take(size_of::())(input)?; + let (input, chunk_data_size) = take(size_of::())(input)?; + let (input, subsystem_string_offset) = take(size_of::())(input)?; + let (input, process_info_entries_offset) = take(size_of::())(input)?; + let (input, number_process_entries) = take(size_of::())(input)?; + let (input, catalog_sub_chunks_offset) = take(size_of::())(input)?; + let (input, number_sub_chunks) = take(size_of::())(input)?; + + let unknown_length: u8 = 6; + let (input, unknown) = take(unknown_length)(input)?; + let (mut input, earliest_firehose_timestamp) = take(size_of::())(input)?; + + let (_, catalog_chunk_tag) = le_u32(chunk_tag)?; + let (_, catalog_chunk_sub_tag) = le_u32(chunk_sub_tag)?; + let (_, catalog_chunk_data_size) = le_u64(chunk_data_size)?; + let (_, catalog_subsystem_string_offset) = le_u16(subsystem_string_offset)?; + let (_, catalog_process_info_entries_offset) = le_u16(process_info_entries_offset)?; + let (_, catalog_number_process_entries) = le_u16(number_process_entries)?; + + let (_, catalog_catalog_sub_chunks_offset) = le_u16(catalog_sub_chunks_offset)?; + let (_, catalog_number_sub_chunks) = le_u16(number_sub_chunks)?; + let (_, earliest_firehose) = le_u64(earliest_firehose_timestamp)?; + + let uuid_length = 16; + let number_catalog_uuids = catalog_subsystem_string_offset / uuid_length; + let mut uuid_count = 0; + + // Nom all UUIDs based on offset of subsystem strings (offset divided by uuid length equals number of uuids) + // UUIDs are 16 bytes + while uuid_count < number_catalog_uuids { + let (input_data, uuid) = take(size_of::())(input)?; + let (_, uuid_be) = be_u128(uuid)?; + + catalog_chunk + .catalog_uuids + .push(format!("{:032X}", uuid_be)); + uuid_count += 1; + input = input_data + } + + catalog_chunk.chunk_tag = catalog_chunk_tag; + catalog_chunk.chunk_sub_tag = catalog_chunk_sub_tag; + catalog_chunk.chunk_data_size = catalog_chunk_data_size; + catalog_chunk.catalog_subsystem_strings_offset = catalog_subsystem_string_offset; + catalog_chunk.catalog_process_info_entries_offset = catalog_process_info_entries_offset; + catalog_chunk.number_process_information_entries = catalog_number_process_entries; + catalog_chunk.catalog_offset_sub_chunks = catalog_catalog_sub_chunks_offset; + catalog_chunk.number_sub_chunks = catalog_number_sub_chunks; + catalog_chunk.chunk_sub_tag = catalog_chunk_sub_tag; + catalog_chunk.unknown = unknown.to_vec(); + catalog_chunk.earliest_firehose_timestamp = earliest_firehose; + + // Nom all subystem strings. Total length equals catalog_process_info_entries_offset minus catalog_subsystem_string_offset + let subsystems_strings_length = + catalog_process_info_entries_offset - catalog_subsystem_string_offset; + let (mut input, subsystem_strings_data) = take(subsystems_strings_length)(input)?; + catalog_chunk.catalog_subsystem_strings = subsystem_strings_data.to_vec(); + + let mut proc_entry_count = 0; + while proc_entry_count < catalog_chunk.number_process_information_entries { + // Parse and get Process Entry data + let (proc_input, mut process_entries) = + CatalogChunk::parse_catalog_process_entry(input, &catalog_chunk.catalog_uuids)?; + + // Grab parsed UUIDs from Catalag array based on process entry uuid index + for (key, uuid) in catalog_chunk.catalog_uuids.iter().enumerate() { + if process_entries.catalog_main_uuid_index == key as u16 { + process_entries.main_uuid = uuid.to_string(); + } + if process_entries.catalog_dsc_uuid_index == key as u16 { + process_entries.dsc_uuid = uuid.to_string(); + } + } + + input = proc_input; + proc_entry_count += 1; + catalog_chunk + .catalog_process_info_entries + .push(process_entries); + } + + let mut subchunk_count = 0; + + while subchunk_count < catalog_chunk.number_sub_chunks { + // Get Catalog subchunk metadata + let (subchunk_input, subchunks) = CatalogChunk::parse_catalog_subchunk(input)?; + + input = subchunk_input; + subchunk_count += 1; + catalog_chunk.catalog_subchunks.push(subchunks); + } + + Ok((input, catalog_chunk)) + } + + // Parse the Catalog Process Information entry + fn parse_catalog_process_entry<'a>( + data: &'a [u8], + uuids: &[String], + ) -> nom::IResult<&'a [u8], ProcessInfoEntry> { + let mut catalog_process_entry = ProcessInfoEntry { + index: 0, + unknown: 0, + catalog_main_uuid_index: 0, + catalog_dsc_uuid_index: 0, + first_number_proc_id: 0, + second_number_proc_id: 0, + pid: 0, + effective_user_id: 0, + unknown2: 0, + number_uuids_entries: 0, + unknown3: 0, + uuid_info_entries: Vec::new(), + number_subsystems: 0, + unknown4: 0, + subsystem_entries: Vec::new(), + main_uuid: String::new(), + dsc_uuid: String::new(), + }; + + // Get all static sized data + let (input, index) = take(size_of::())(data)?; + let (input, unknown) = take(size_of::())(input)?; + let (input, catalog_main_uuid_index) = take(size_of::())(input)?; + let (input, catalog_dsc_uuid_index) = take(size_of::())(input)?; + let (input, first_number_proc_id) = take(size_of::())(input)?; + let (input, second_number_proc_id) = take(size_of::())(input)?; + let (input, pid) = take(size_of::())(input)?; + let (input, effective_user_id) = take(size_of::())(input)?; + let (input, unknown2) = take(size_of::())(input)?; + let (input, number_uuids_entries) = take(size_of::())(input)?; + let (mut input, unknown3) = take(size_of::())(input)?; + + let (_, process_index) = le_u16(index)?; + let (_, process_unknown) = le_u16(unknown)?; + let (_, process_catalog_main_uuid_index) = le_u16(catalog_main_uuid_index)?; + let (_, process_catalog_dsc_uuid_index) = le_u16(catalog_dsc_uuid_index)?; + let (_, process_first_number_proc_id) = le_u64(first_number_proc_id)?; + let (_, process_second_number_proc_id) = le_u32(second_number_proc_id)?; + let (_, process_pid) = le_u32(pid)?; + let (_, process_effective_user_id) = le_u32(effective_user_id)?; + let (_, process_unknown2) = le_u32(unknown2)?; + let (_, process_number_uuids_entries) = le_u32(number_uuids_entries)?; + let (_, process_unknown3) = le_u32(unknown3)?; + + catalog_process_entry.index = process_index; + catalog_process_entry.unknown = process_unknown; + catalog_process_entry.catalog_main_uuid_index = process_catalog_main_uuid_index; + catalog_process_entry.catalog_dsc_uuid_index = process_catalog_dsc_uuid_index; + catalog_process_entry.first_number_proc_id = process_first_number_proc_id; + catalog_process_entry.second_number_proc_id = process_second_number_proc_id; + catalog_process_entry.pid = process_pid; + catalog_process_entry.effective_user_id = process_effective_user_id; + catalog_process_entry.unknown2 = process_unknown2; + catalog_process_entry.number_uuids_entries = process_number_uuids_entries; + catalog_process_entry.unknown3 = process_unknown3; + + // Continously get uuid entries based on number_uuids_entries + let mut uuid_entries = 0; + while uuid_entries < catalog_process_entry.number_uuids_entries { + // Parse UUID metadata in Catalog Process Entry (the Catalog Process Entry references the UUIDs array parsed in parse_catalog by index) + let process_uuid_metadata_result = CatalogChunk::parse_process_info_uuid_entry(input); + match process_uuid_metadata_result { + Ok((process_input, mut uuid_data)) => { + if uuids.len() < uuid_data.catalog_uuid_index as usize { + error!("Catalog Process UUID Index greater than Catalog UUID Array. Log is likely corrupted"); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + uuid_data.uuid = uuids[uuid_data.catalog_uuid_index as usize].to_owned(); + input = process_input; + uuid_entries += 1; + catalog_process_entry.uuid_info_entries.push(uuid_data); + } + Err(err) => { + error!("Failed to parse Catalog Process Entry: {:?}", err); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + } + + // Get static sized data after getting uuid entries + let (input, number_subsystems) = take(size_of::())(input)?; + let (mut input, unknown4) = take(size_of::())(input)?; + let (_, process_number_subsystems) = le_u32(number_subsystems)?; + let (_, process_unknown4) = le_u32(unknown4)?; + catalog_process_entry.number_subsystems = process_number_subsystems; + catalog_process_entry.unknown4 = process_unknown4; + + // Continuously get subsystem entries based on number_subsystems + let mut subsystem_entries = 0; + while subsystem_entries < catalog_process_entry.number_subsystems { + let (process_input, subsystem) = CatalogChunk::parse_process_info_subystem(input)?; + input = process_input; + subsystem_entries += 1; + catalog_process_entry.subsystem_entries.push(subsystem); + } + let subsystem_size = 6; + let total_subsystem_size = catalog_process_entry.number_subsystems * subsystem_size; + + let padding = padding_size(total_subsystem_size.into()); + let (input, _) = take(padding)(input)?; + + Ok((input, catalog_process_entry)) + } + + // Parse the UUID metadata in the Catalog Process Entry (the Catalog Process Entry references the UUIDs array parsed in parse_catalog by index value) + fn parse_process_info_uuid_entry( + data: &[u8], + ) -> nom::IResult<&[u8], ProcessUUIDEntry, CatalogProcessUUIDEntryError> { + let mut process_uuid = ProcessUUIDEntry { + size: 0, + unknown: 0, + catalog_uuid_index: 0, + load_address: 0, + uuid: String::new(), + }; + + let (input, size) = take(size_of::())(data)?; + let (input, unknown) = take(size_of::())(input)?; + let (input, catalog_uuid_index) = take(size_of::())(input)?; + + let load_address_size: u8 = 6; + let (input, load_address) = take(load_address_size)(input)?; + + let (_, process_uuid_size) = le_u32(size)?; + let (_, process_uuid_unknown) = le_u32(unknown)?; + let (_, process_uuid_catalog_uuid_index) = le_u16(catalog_uuid_index)?; + + // Add padding to the load address offset + let mut load_address_vec = load_address.to_vec(); + load_address_vec.push(0); + load_address_vec.push(0); + let mut load_address_buff: &[u8] = &load_address_vec; + let process_load_address_result = load_address_buff.read_u64::(); + match process_load_address_result { + Ok(process_load_address) => process_uuid.load_address = process_load_address, + Err(err) => { + error!( + "Failed to get Little Endian value of Catalog Process Entry load address: {:?}", + err + ); + return Err(nom::Err::Failure(CatalogProcessUUIDEntryError { + message: String::from("failed to get Little Endian value"), + })); + } + } + + process_uuid.size = process_uuid_size; + process_uuid.unknown = process_uuid_unknown; + process_uuid.catalog_uuid_index = process_uuid_catalog_uuid_index; + + Ok((input, process_uuid)) + } + + // Parse the Catalog Subsystem metadata. This helps get the subsystem (App Bundle ID) and the log entry category + fn parse_process_info_subystem(data: &[u8]) -> nom::IResult<&[u8], ProcessInfoSubsystem> { + let mut process_subsystem = ProcessInfoSubsystem { + identifer: 0, + subsystem_offset: 0, + category_offset: 0, + }; + + let (input, identifer) = take(size_of::())(data)?; + let (input, subsystem_offset) = take(size_of::())(input)?; + let (input, category_offset) = take(size_of::())(input)?; + + let (_, process_identifier) = le_u16(identifer)?; + let (_, process_subystem_offset) = le_u16(subsystem_offset)?; + let (_, process_category_offset) = le_u16(category_offset)?; + + process_subsystem.identifer = process_identifier; + process_subsystem.subsystem_offset = process_subystem_offset; + process_subsystem.category_offset = process_category_offset; + + Ok((input, process_subsystem)) + } + + // Parse the Catalog Subchunk metadata. This metadata is related to the compressed (typically) Chunkset data + fn parse_catalog_subchunk(data: &[u8]) -> nom::IResult<&[u8], CatalogSubchunk> { + let mut catalog_subchunk = CatalogSubchunk { + start: 0, + end: 0, + uncompressed_size: 0, + compression_algorithm: 0, + number_index: 0, + indexes: Vec::new(), + number_string_offsets: 0, + string_offsets: Vec::new(), + }; + + // Get static size subchunk data + let (input, start) = take(size_of::())(data)?; + let (input, end) = take(size_of::())(input)?; + let (input, uncompressed_size) = take(size_of::())(input)?; + let (input, compression_algorithm) = take(size_of::())(input)?; + let (mut input, number_indexes) = take(size_of::())(input)?; + + let (_, subchunk_start) = le_u64(start)?; + let (_, subchunk_end) = le_u64(end)?; + let (_, subchunk_uncompressed_size) = le_u32(uncompressed_size)?; + let (_, subchunk_compression_algorithm) = le_u32(compression_algorithm)?; + let (_, subchunk_number_indexes) = le_u32(number_indexes)?; + + // If the data is compressed (typically) the compression type should be 0x100 (256) which is LZ compressed + let lz4_compressions = 256; + if subchunk_compression_algorithm != lz4_compressions { + error!( + "Unknown compression algorithm: {}", + subchunk_compression_algorithm + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + + catalog_subchunk.start = subchunk_start; + catalog_subchunk.end = subchunk_end; + catalog_subchunk.uncompressed_size = subchunk_uncompressed_size; + catalog_subchunk.compression_algorithm = subchunk_compression_algorithm; + catalog_subchunk.number_index = subchunk_number_indexes; + + let mut index_count = 0; + while index_count < subchunk_number_indexes { + let (index_input, index) = take(size_of::())(input)?; + let (_, subchunk_index) = le_u16(index)?; + catalog_subchunk.indexes.push(subchunk_index); + index_count += 1; + input = index_input; + } + + let (mut input, number_string_offsets) = take(size_of::())(input)?; + let (_, subchunk_string_number_offsets) = le_u32(number_string_offsets)?; + catalog_subchunk.number_string_offsets = subchunk_string_number_offsets; + + let mut strings_count = 0; + while strings_count < subchunk_string_number_offsets { + let (index_input, strings) = take(size_of::())(input)?; + let (_, subchunk_strings_offset) = le_u16(strings)?; + catalog_subchunk + .string_offsets + .push(subchunk_strings_offset); + strings_count += 1; + + input = index_input; + } + + // calculate amount of padding needed based on number_string_offsets and number_index + let offset_size = 2; + let total_subchunk_size = catalog_subchunk.number_string_offsets * offset_size + + (catalog_subchunk.number_index * offset_size); + let padding = padding_size(u64::from(total_subchunk_size)); + let (input, _) = take(padding)(input)?; + + Ok((input, catalog_subchunk)) + } + + // Get subsystem and category based on the log entry first_proc_id, second_proc_id, log entry subsystem id and the associated Catalog + pub fn get_subsystem<'a>( + subsystem_value: &u16, + first_proc_id: &u64, + second_proc_id: &u32, + catalog: &'a CatalogChunk, + ) -> nom::IResult<&'a [u8], SubsystemInfo> { + let mut subsystem_info = SubsystemInfo { + subsystem: String::new(), + category: String::new(), + }; + + // Go through catalog entries until first and second proc id match the log entry + for process_info in &catalog.catalog_process_info_entries { + if first_proc_id == &process_info.first_number_proc_id + && second_proc_id == &process_info.second_number_proc_id + { + // Go through subsystems in catalog entry until subsystem value is found + for subsystems in &process_info.subsystem_entries { + if subsystem_value == &subsystems.identifer { + let subsystem_data: &[u8] = &catalog.catalog_subsystem_strings; + let (input, _) = take(subsystems.subsystem_offset)(subsystem_data)?; + let (_, subsystem_string) = extract_string(input)?; + + let (input, _) = take(subsystems.category_offset)(subsystem_data)?; + let (_, category_string) = extract_string(input)?; + subsystem_info.subsystem = subsystem_string; + subsystem_info.category = category_string; + return Ok((input, subsystem_info)); + } + } + } + } + + warn!("[macos-unifiedlogs] Did not find subsystem in log entry"); + subsystem_info.subsystem = String::from("Unknown subsystem"); + Ok((&[], subsystem_info)) + } + + // Get the actual Process ID associated with log entry + pub fn get_pid(first_proc_id: &u64, second_proc_id: &u32, catalog: &CatalogChunk) -> u64 { + // Go through catalog entries until first and second proc id match the log entry + for process_info in &catalog.catalog_process_info_entries { + if first_proc_id == &process_info.first_number_proc_id + && second_proc_id == &process_info.second_number_proc_id + { + return u64::from(process_info.pid); + } + } + + warn!("[macos-unifiedlogs] Did not find PID in log Catalog"); + 0 + } + + // Get the effictive user id associated with log entry. Can be mapped to an account name + pub fn get_euid(first_proc_id: &u64, second_proc_id: &u32, catalog: &CatalogChunk) -> u32 { + // Go through catalog entries until first and second proc id match the log entry + for process_info in &catalog.catalog_process_info_entries { + if first_proc_id == &process_info.first_number_proc_id + && second_proc_id == &process_info.second_number_proc_id + { + return process_info.effective_user_id; + } + } + warn!("[macos-unifiedlogs] Did not find EUID in log Catalog"); + 0 + } +} + +#[cfg(test)] +mod tests { + use super::CatalogChunk; + use std::fs; + use std::path::PathBuf; + + #[test] + fn test_parse_catalog() { + let test_chunk_catalog = [ + 11, 96, 0, 0, 17, 0, 0, 0, 208, 1, 0, 0, 0, 0, 0, 0, 32, 0, 96, 0, 1, 0, 160, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 20, 165, 44, 35, 253, 233, 2, 0, 43, 239, 210, 12, 24, 236, 56, 56, + 129, 79, 43, 78, 90, 243, 188, 236, 61, 5, 132, 95, 63, 101, 53, 143, 158, 191, 34, 54, + 231, 114, 172, 1, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 83, 107, 121, 76, 105, + 103, 104, 116, 0, 112, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 95, 105, 110, + 115, 116, 114, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 0, 116, 114, 97, 99, + 105, 110, 103, 46, 115, 116, 97, 108, 108, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 158, + 0, 0, 0, 0, 0, 0, 0, 55, 1, 0, 0, 158, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 19, 0, 78, 0, 0, 0, 47, 0, 0, 0, 0, 0, + 246, 113, 118, 43, 250, 233, 2, 0, 62, 195, 90, 26, 9, 234, 2, 0, 120, 255, 0, 0, 0, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 48, 89, 60, 28, 9, 234, 2, 0, + 99, 50, 207, 40, 18, 234, 2, 0, 112, 240, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 19, 0, 47, 0, 153, 6, 208, 41, 18, 234, 2, 0, 0, 214, 108, 78, 32, 234, 2, 0, + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 128, 0, 87, + 79, 32, 234, 2, 0, 137, 5, 2, 205, 41, 234, 2, 0, 88, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 185, 11, 2, 205, 41, 234, 2, 0, 172, 57, 107, + 20, 56, 234, 2, 0, 152, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, + 0, 47, 0, 53, 172, 105, 21, 56, 234, 2, 0, 170, 167, 194, 43, 68, 234, 2, 0, 144, 255, + 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 220, 202, 171, 57, + 68, 234, 2, 0, 119, 171, 170, 119, 76, 234, 2, 0, 240, 254, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, + ]; + + let (_, catalog_data) = CatalogChunk::parse_catalog(&test_chunk_catalog).unwrap(); + + assert_eq!(catalog_data.chunk_tag, 0x600b); + assert_eq!(catalog_data.chunk_sub_tag, 17); + assert_eq!(catalog_data.chunk_data_size, 464); + assert_eq!(catalog_data.catalog_subsystem_strings_offset, 32); + assert_eq!(catalog_data.catalog_process_info_entries_offset, 96); + assert_eq!(catalog_data.number_process_information_entries, 1); + assert_eq!(catalog_data.catalog_offset_sub_chunks, 160); + assert_eq!(catalog_data.number_sub_chunks, 7); + assert_eq!(catalog_data.unknown, [0, 0, 0, 0, 0, 0]); + assert_eq!(catalog_data.earliest_firehose_timestamp, 820223379547412); + assert_eq!( + catalog_data.catalog_uuids, + [ + "2BEFD20C18EC3838814F2B4E5AF3BCEC", + "3D05845F3F65358F9EBF2236E772AC01" + ] + ); + assert_eq!( + catalog_data.catalog_subsystem_strings, + [ + 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 83, 107, 121, 76, 105, 103, 104, 116, + 0, 112, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 95, 105, 110, 115, 116, + 114, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 0, 116, 114, 97, 99, 105, + 110, 103, 46, 115, 116, 97, 108, 108, 115, 0, 0, 0 + ] + ); + assert_eq!(catalog_data.catalog_process_info_entries.len(), 1); + assert_eq!( + catalog_data.catalog_process_info_entries[0].main_uuid, + "2BEFD20C18EC3838814F2B4E5AF3BCEC" + ); + assert_eq!( + catalog_data.catalog_process_info_entries[0].dsc_uuid, + "3D05845F3F65358F9EBF2236E772AC01" + ); + + assert_eq!(catalog_data.catalog_subchunks.len(), 7) + } + + #[test] + fn test_parse_catalog_process_entry() { + let subsystem_data = [ + 0, 0, 0, 0, 0, 0, 1, 0, 158, 0, 0, 0, 0, 0, 0, 0, 55, 1, 0, 0, 158, 0, 0, 0, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 19, 0, 78, + 0, 0, 0, 47, 0, 0, 0, 0, 0, 246, 113, 118, 43, 250, 233, 2, 0, 62, 195, 90, 26, 9, 234, + 2, 0, 120, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 48, + 89, 60, 28, 9, 234, 2, 0, 99, 50, 207, 40, 18, 234, 2, 0, 112, 240, 0, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 153, 6, 208, 41, 18, 234, 2, 0, 0, + 214, 108, 78, 32, 234, 2, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 19, 0, 47, 0, 128, 0, 87, 79, 32, 234, 2, 0, 137, 5, 2, 205, 41, 234, 2, 0, 88, 255, + 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 185, 11, 2, 205, + 41, 234, 2, 0, 172, 57, 107, 20, 56, 234, 2, 0, 152, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 53, 172, 105, 21, 56, 234, 2, 0, 170, 167, 194, + 43, 68, 234, 2, 0, 144, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, + 0, 47, 0, 220, 202, 171, 57, 68, 234, 2, 0, 119, 171, 170, 119, 76, 234, 2, 0, 240, + 254, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, + ]; + + let test_data = vec![String::from("0")]; + + let (_, process_entry) = + CatalogChunk::parse_catalog_process_entry(&subsystem_data, &test_data).unwrap(); + assert_eq!(process_entry.index, 0); + assert_eq!(process_entry.unknown, 0); + assert_eq!(process_entry.catalog_main_uuid_index, 0); + assert_eq!(process_entry.catalog_dsc_uuid_index, 1); + assert_eq!(process_entry.first_number_proc_id, 158); + assert_eq!(process_entry.second_number_proc_id, 311); + assert_eq!(process_entry.pid, 158); + assert_eq!(process_entry.effective_user_id, 88); + assert_eq!(process_entry.unknown2, 0); + assert_eq!(process_entry.number_uuids_entries, 0); + assert_eq!(process_entry.unknown3, 0); + assert_eq!(process_entry.uuid_info_entries.len(), 0); + assert_eq!(process_entry.number_subsystems, 2); + assert_eq!(process_entry.unknown4, 0); + assert_eq!(process_entry.subsystem_entries.len(), 2); + assert_eq!(process_entry.main_uuid, ""); + assert_eq!(process_entry.dsc_uuid, ""); + } + + #[test] + fn test_parse_process_info_uuid_entry() { + let test_subsystem_data = [ + 87, 0, 0, 0, 19, 0, 78, 0, 0, 0, 47, 0, 0, 0, 0, 0, 246, 113, 118, 43, 250, 233, 2, 0, + 62, 195, 90, 26, 9, 234, 2, 0, 120, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 19, 0, 47, 0, 48, 89, 60, 28, 9, 234, 2, 0, 99, 50, 207, 40, 18, 234, 2, 0, + 112, 240, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 153, 6, + 208, 41, 18, 234, 2, 0, 0, 214, 108, 78, 32, 234, 2, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, + 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 128, 0, 87, 79, 32, 234, 2, 0, 137, 5, 2, + 205, 41, 234, 2, 0, 88, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, + 0, 47, 0, 185, 11, 2, 205, 41, 234, 2, 0, 172, 57, 107, 20, 56, 234, 2, 0, 152, 255, 0, + 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 53, 172, 105, 21, 56, + 234, 2, 0, 170, 167, 194, 43, 68, 234, 2, 0, 144, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 220, 202, 171, 57, 68, 234, 2, 0, 119, 171, 170, + 119, 76, 234, 2, 0, 240, 254, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, + 0, 47, 0, + ]; + + let (data, subsystems) = + CatalogChunk::parse_process_info_subystem(&test_subsystem_data).unwrap(); + assert_eq!(subsystems.identifer, 87); + assert_eq!(subsystems.subsystem_offset, 0); + assert_eq!(subsystems.category_offset, 19); + + let (_, subsystems) = CatalogChunk::parse_process_info_subystem(&data).unwrap(); + assert_eq!(subsystems.identifer, 78); + assert_eq!(subsystems.subsystem_offset, 0); + assert_eq!(subsystems.category_offset, 47); + } + + #[test] + fn test_parse_catalog_subchunk() { + let test_subchunks = [ + 246, 113, 118, 43, 250, 233, 2, 0, 62, 195, 90, 26, 9, 234, 2, 0, 120, 255, 0, 0, 0, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 48, 89, 60, 28, 9, 234, 2, 0, + 99, 50, 207, 40, 18, 234, 2, 0, 112, 240, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 19, 0, 47, 0, 153, 6, 208, 41, 18, 234, 2, 0, 0, 214, 108, 78, 32, 234, 2, 0, + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 128, 0, 87, + 79, 32, 234, 2, 0, 137, 5, 2, 205, 41, 234, 2, 0, 88, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 185, 11, 2, 205, 41, 234, 2, 0, 172, 57, 107, + 20, 56, 234, 2, 0, 152, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, + 0, 47, 0, 53, 172, 105, 21, 56, 234, 2, 0, 170, 167, 194, 43, 68, 234, 2, 0, 144, 255, + 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 220, 202, 171, 57, + 68, 234, 2, 0, 119, 171, 170, 119, 76, 234, 2, 0, 240, 254, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, + ]; + + let (data, subchunk) = CatalogChunk::parse_catalog_subchunk(&test_subchunks).unwrap(); + assert_eq!(subchunk.start, 820210633699830); + assert_eq!(subchunk.end, 820274771182398); + assert_eq!(subchunk.uncompressed_size, 65400); + assert_eq!(subchunk.compression_algorithm, 256); + assert_eq!(subchunk.number_index, 1); + assert_eq!(subchunk.indexes, [0]); + assert_eq!(subchunk.number_string_offsets, 3); + assert_eq!(subchunk.string_offsets, [0, 19, 47]); + + let (data, subchunk) = CatalogChunk::parse_catalog_subchunk(&data).unwrap(); + assert_eq!(subchunk.start, 820274802743600); + assert_eq!(subchunk.end, 820313668399715); + assert_eq!(subchunk.uncompressed_size, 61552); + assert_eq!(subchunk.compression_algorithm, 256); + assert_eq!(subchunk.number_index, 1); + assert_eq!(subchunk.indexes, [0]); + assert_eq!(subchunk.number_string_offsets, 3); + assert_eq!(subchunk.string_offsets, [0, 19, 47]); + + let (_, subchunk) = CatalogChunk::parse_catalog_subchunk(&data).unwrap(); + assert_eq!(subchunk.start, 820313685231257); + assert_eq!(subchunk.end, 820374429029888); + assert_eq!(subchunk.uncompressed_size, 65536); + assert_eq!(subchunk.compression_algorithm, 256); + assert_eq!(subchunk.number_index, 1); + assert_eq!(subchunk.indexes, [0]); + assert_eq!(subchunk.number_string_offsets, 3); + assert_eq!(subchunk.string_offsets, [0, 19, 47]); + } + + #[test] + #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: Incomplete(Unknown)")] + fn test_parse_catalog_subchunk_bad_compression() { + let test_bad_compression = [ + 246, 113, 118, 43, 250, 233, 2, 0, 62, 195, 90, 26, 9, 234, 2, 0, 120, 255, 0, 0, 0, 2, + 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 48, 89, 60, 28, 9, 234, 2, 0, + 99, 50, 207, 40, 18, 234, 2, 0, 112, 240, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 19, 0, 47, 0, 153, 6, 208, 41, 18, 234, 2, 0, 0, 214, 108, 78, 32, 234, 2, 0, + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 128, 0, 87, + 79, 32, 234, 2, 0, 137, 5, 2, 205, 41, 234, 2, 0, 88, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 185, 11, 2, 205, 41, 234, 2, 0, 172, 57, 107, + 20, 56, 234, 2, 0, 152, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, + 0, 47, 0, 53, 172, 105, 21, 56, 234, 2, 0, 170, 167, 194, 43, 68, 234, 2, 0, 144, 255, + 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 220, 202, 171, 57, + 68, 234, 2, 0, 119, 171, 170, 119, 76, 234, 2, 0, 240, 254, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, + ]; + let (_, _) = CatalogChunk::parse_catalog_subchunk(&test_bad_compression).unwrap(); + } + + #[test] + fn test_get_big_sur_subsystem() { + let subsystem_value = 4; + let first_proc_id = 165; + let second_proc_id = 406; + + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Catalog Tests/big_sur_catalog.raw"); + let buffer = fs::read(test_path).unwrap(); + + let (_, catalog) = CatalogChunk::parse_catalog(&buffer).unwrap(); + + let (_, results) = CatalogChunk::get_subsystem( + &subsystem_value, + &first_proc_id, + &second_proc_id, + &catalog, + ) + .unwrap(); + assert_eq!(results.subsystem, "com.apple.containermanager"); + assert_eq!(results.category, "xpc"); + } +} diff --git a/src/chunks/firehose/activity.rs b/src/chunks/firehose/activity.rs new file mode 100755 index 0000000..449a1ba --- /dev/null +++ b/src/chunks/firehose/activity.rs @@ -0,0 +1,326 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use crate::catalog::CatalogChunk; +use crate::chunks::firehose::flags::FirehoseFormatters; +use crate::chunks::firehose::message::MessageData; +use crate::dsc::SharedCacheStrings; +use crate::uuidtext::UUIDText; +use log::{debug, error}; +use nom::Needed; +use nom::{ + bytes::complete::take, + number::complete::{le_u32, le_u64}, +}; +use std::mem::size_of; + +#[derive(Debug, Clone)] +pub struct FirehoseActivity { + pub unknown_activity_id: u32, + pub unknown_sentinal: u32, // always 0x80000000? + pub pid: u64, // if flag 0x0010 + pub unknown_activity_id_2: u32, // if flag 0x0001 + pub unknown_sentinal_2: u32, // always 0x80000000? only if flag 0x0001 + pub unknown_activity_id_3: u32, // if flag 0x0200 + pub unknown_sentinal_3: u32, // always 0x80000000? only if flag 0x0200 + pub unknown_message_string_ref: u32, + pub unknown_pc_id: u32, // Appears to be used to calculate string offset for firehose events with Absolute flag + pub firehose_formatters: FirehoseFormatters, +} + +impl FirehoseActivity { + /// Parse Activity Type Firehose log entry. + // Ex: tp 3536 + 60: activity create (has_current_aid, has_unique_pid, shared_cache, has_other_aid) + pub fn parse_activity<'a>( + data: &'a [u8], + firehose_flags: &u16, + firehose_log_type: &u8, + ) -> nom::IResult<&'a [u8], FirehoseActivity> { + let mut activity = FirehoseActivity { + unknown_activity_id: 0, + unknown_sentinal: 0, + pid: 0, + unknown_activity_id_2: 0, + unknown_sentinal_2: 0, + unknown_activity_id_3: 0, + unknown_sentinal_3: 0, + unknown_message_string_ref: 0, + unknown_pc_id: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + }; + let mut input = data; + + // Useraction activity type does not have first Activity ID or sentinel + let useraction: u8 = 0x3; + // Get first activity_id (if not useraction type) + if firehose_log_type != &useraction { + let (firehose_input, unknown_activity_id) = take(size_of::())(data)?; + let (firehose_input, unknown_sentinel) = take(size_of::())(firehose_input)?; + let (_, firehose_unknown_activity_id) = le_u32(unknown_activity_id)?; + let (_, firehose_unknown_sentinel) = le_u32(unknown_sentinel)?; + activity.unknown_activity_id = firehose_unknown_activity_id; + activity.unknown_sentinal = firehose_unknown_sentinel; + input = firehose_input; + } + + let unique_pid: u16 = 0x10; // has_unique_pid flag + if (firehose_flags & unique_pid) != 0 { + debug!("[macos-unifiedlogs] Activity Firehose log chunk has unique_pid flag"); + let (firehose_input, unique_pid) = take(size_of::())(input)?; + let (_, firehose_unique_pid) = le_u64(unique_pid)?; + activity.pid = firehose_unique_pid; + input = firehose_input; + } + + let activity_id_current: u16 = 0x1; // has_current_aid flag + if (firehose_flags & activity_id_current) != 0 { + debug!("[macos-unifiedlogs] Activity Firehose log chunk has has_current_aid flag"); + let (firehose_input, unknown_activity_id) = take(size_of::())(input)?; + let (firehose_input, unknown_sentinel) = take(size_of::())(firehose_input)?; + let (_, firehose_unknown_activity_id) = le_u32(unknown_activity_id)?; + let (_, firehose_unknown_sentinel) = le_u32(unknown_sentinel)?; + activity.unknown_activity_id_2 = firehose_unknown_activity_id; + activity.unknown_sentinal_2 = firehose_unknown_sentinel; + input = firehose_input; + } + + let activity_id_other: u16 = 0x200; // has_other_current_aid flag. In Activity log entries this is another activity id flag + if (firehose_flags & activity_id_other) != 0 { + debug!( + "[macos-unifiedlogs] Activity Firehose log chunk has has_other_current_aid flag" + ); + let (firehose_input, unknown_activity_id) = take(size_of::())(input)?; + let (firehose_input, unknown_sentinel) = take(size_of::())(firehose_input)?; + let (_, firehose_unknown_activity_id) = le_u32(unknown_activity_id)?; + let (_, firehose_unknown_sentinel) = le_u32(unknown_sentinel)?; + activity.unknown_activity_id_3 = firehose_unknown_activity_id; + activity.unknown_sentinal_3 = firehose_unknown_sentinel; + input = firehose_input; + } + let (input, unknown_pc_id) = take(size_of::())(input)?; + let (_, firehose_unknown_pc_id) = le_u32(unknown_pc_id)?; + activity.unknown_pc_id = firehose_unknown_pc_id; // Unknown (Message string reference)?? PC ID? + + // Check for flags related to base string format location (shared string file (dsc) or UUID file) + let (input, formatters) = + FirehoseFormatters::firehose_formatter_flags(input, firehose_flags)?; + activity.firehose_formatters = formatters; + Ok((input, activity)) + } + + /// Get base log message string formatter from shared cache strings (dsc) or UUID text file for firehose activity log entries (chunks) + pub fn get_firehose_activity_strings<'a>( + firehose: &FirehoseActivity, + strings_data: &'a [UUIDText], + shared_strings: &'a [SharedCacheStrings], + string_offset: u64, + first_proc_id: &u64, + second_proc_id: &u32, + catalogs: &CatalogChunk, + ) -> nom::IResult<&'a [u8], MessageData> { + if firehose.firehose_formatters.shared_cache + || (firehose.firehose_formatters.large_shared_cache != 0 + && firehose.firehose_formatters.has_large_offset != 0) + { + if firehose.firehose_formatters.has_large_offset != 0 { + let mut large_offset = firehose.firehose_formatters.has_large_offset; + // large_shared_cache should be double the value of has_large_offset + // Ex: has_large_offset = 1, large_shared_cache = 2 + // If the value do not match then there is an issue with shared string offset + // Can recover by using large_shared_cache + // Apple records this as an error: "error: ~~> " + // But is still able to get string formatter + if large_offset != firehose.firehose_formatters.large_shared_cache / 2 + && !firehose.firehose_formatters.shared_cache + { + large_offset = firehose.firehose_formatters.large_shared_cache / 2; + } + // Large offset is 8 if shared_cache flag is set + if firehose.firehose_formatters.shared_cache { + large_offset = 8; + } + // Combine large offset value with current string offset to get the true offset + let extra_offset_value = format!("{:X}{:07X}", large_offset, string_offset); + + let extra_offset_value_result = u64::from_str_radix(&extra_offset_value, 16); + match extra_offset_value_result { + Ok(offset) => { + return MessageData::extract_shared_strings( + shared_strings, + strings_data, + offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + Err(err) => { + // We should not get errors since we are combining two numbers to create the offset + error!( + "Failed to get shared string offset to format string for activity firehose entry: {:?}", + err + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + } + MessageData::extract_shared_strings( + shared_strings, + strings_data, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ) + } else { + if firehose.firehose_formatters.absolute { + let extra_offset_value = format!( + "{:X}{:08X}", + firehose.firehose_formatters.main_exe_alt_index, firehose.unknown_pc_id, + ); + let offset_result = u64::from_str_radix(&extra_offset_value, 16); + match offset_result { + Ok(offset) => { + return MessageData::extract_absolute_strings( + strings_data, + offset, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + Err(err) => { + // We should not get errors since we are combining two numbers to create the offset + error!("Failed to get absolute offset to format string for activity firehose entry: {:?}", err); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + } + if !firehose.firehose_formatters.uuid_relative.is_empty() { + return MessageData::extract_alt_uuid_strings( + strings_data, + string_offset, + &firehose.firehose_formatters.uuid_relative, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + MessageData::extract_format_strings( + strings_data, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ) + } + } +} + +#[cfg(test)] +mod tests { + use super::FirehoseActivity; + use crate::parser::{collect_shared_strings, collect_strings, parse_log}; + use std::path::PathBuf; + + #[test] + fn test_parse_activity() { + let test_data = [ + 178, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 178, 251, 0, 0, 0, 0, 0, 128, + 179, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, + ]; + let test_flags = 573; + let log_type: u8 = 0x1; + let (_, results) = + FirehoseActivity::parse_activity(&test_data, &test_flags, &log_type).unwrap(); + assert_eq!(results.unknown_activity_id, 64434); + assert_eq!(results.unknown_sentinal, 2147483648); + assert_eq!(results.pid, 236); + assert_eq!(results.unknown_activity_id_2, 64434); + assert_eq!(results.unknown_sentinal_2, 2147483648); + assert_eq!(results.unknown_activity_id_3, 64435); + assert_eq!(results.unknown_sentinal_3, 2147483648); + assert_eq!(results.unknown_message_string_ref, 0); + assert_eq!(results.firehose_formatters.main_exe, false); + assert_eq!(results.firehose_formatters.absolute, false); + assert_eq!(results.firehose_formatters.shared_cache, false); + assert_eq!(results.firehose_formatters.main_plugin, false); + assert_eq!(results.firehose_formatters.pc_style, false); + assert_eq!(results.firehose_formatters.main_exe_alt_index, 0); + assert_eq!(results.firehose_formatters.uuid_relative, ""); + assert_eq!(results.unknown_pc_id, 303578944); + assert_eq!(results.firehose_formatters.has_large_offset, 1); + assert_eq!(results.firehose_formatters.large_shared_cache, 2); + } + + #[test] + fn test_get_firehose_activity_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000004.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let activity_type = 0x2; + + for catalog_data in log_data.catalog_data { + for preamble in catalog_data.firehose { + for firehose in preamble.public_data { + if firehose.unknown_log_activity_type == activity_type { + let (_, message_data) = FirehoseActivity::get_firehose_activity_strings( + &firehose.firehose_activity, + &string_results, + &shared_strings_results, + firehose.format_string_location as u64, + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ) + .unwrap(); + assert_eq!( + message_data.format_string, + "Internal: Check the state of a node" + ); + assert_eq!(message_data.library, "/usr/libexec/opendirectoryd"); + assert_eq!(message_data.process, "/usr/libexec/opendirectoryd"); + assert_eq!( + message_data.process_uuid, + "B736DF1625F538248E9527A8CEC4991E" + ); + assert_eq!( + message_data.library_uuid, + "B736DF1625F538248E9527A8CEC4991E" + ); + return; + } + } + } + } + } +} diff --git a/src/chunks/firehose/firehose_log.rs b/src/chunks/firehose/firehose_log.rs new file mode 100755 index 0000000..980d1d7 --- /dev/null +++ b/src/chunks/firehose/firehose_log.rs @@ -0,0 +1,3537 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::{debug, error, warn}; +use nom::bytes::complete::take_while; +use serde::Serialize; +use std::mem::size_of; + +use crate::chunks::firehose::activity::FirehoseActivity; +use crate::chunks::firehose::flags::FirehoseFormatters; +use crate::chunks::firehose::loss::FirehoseLoss; +use crate::chunks::firehose::nonactivity::FirehoseNonActivity; +use crate::chunks::firehose::signpost::FirehoseSignpost; +use crate::chunks::firehose::trace::FirehoseTrace; +use crate::util::{extract_string_size, padding_size, padding_size_four}; +use nom::number::complete::{be_u128, le_i16, le_i32, le_i64, le_i8}; +use nom::{ + bytes::complete::take, + number::complete::{le_u16, le_u32, le_u64, le_u8}, +}; + +#[derive(Debug, Clone)] +pub struct FirehosePreamble { + pub chunk_tag: u32, + pub chunk_sub_tag: u32, + pub chunk_data_size: u64, + pub first_number_proc_id: u64, + pub second_number_proc_id: u32, + pub ttl: u8, + pub collapsed: u8, + pub unknown: Vec, // reserved? + pub public_data_size: u16, // Size includes the size itself and the 8 bytes below and the public data + pub private_data_virtual_offset: u16, // value is 0x1000 (4096) if there is NO private data + pub unkonwn2: u16, + pub unknown3: u16, + pub base_continous_time: u64, + pub public_data: Vec, +} + +#[derive(Debug, Clone)] +pub struct Firehose { + pub unknown_log_activity_type: u8, // 0x2 is Activity, 0x4 is non-activity, 0x6 is signpost, 0x3 trace + pub unknown_log_type: u8, // Unkonwn but possibly log type (Info/Activity, Debug, Error, Fault, Signpost, System, Default) + pub flags: u16, + pub format_string_location: u32, + pub thread_id: u64, + pub continous_time_delta: u32, + pub continous_time_delta_upper: u16, + pub data_size: u16, + pub firehose_activity: FirehoseActivity, + pub firehose_non_activity: FirehoseNonActivity, + pub firehose_loss: FirehoseLoss, + pub firehose_signpost: FirehoseSignpost, + pub firehose_trace: FirehoseTrace, + pub unknown_item: u8, + pub number_items: u8, + pub message: FirehoseItemData, // Log values extracted +} + +#[derive(Debug)] +pub struct FirehoseItemType { + pub item_type: u8, + item_size: u8, + offset: u16, + message_string_size: u16, + pub message_strings: String, + pub backtrace_strings: Vec, // Only exists if log entry flag "has_context_data" is set +} + +#[derive(Debug, Clone)] +pub struct FirehoseItemData { + pub item_info: Vec, + pub backtrace_strings: Vec, +} + +#[derive(Debug, Clone, Serialize)] +pub struct FirehoseItemInfo { + pub message_strings: String, // The message entry. + pub item_type: u8, // Type of item: strings, numbers, objects, precision + pub item_size: u16, // Size of message in bytes +} + +impl FirehosePreamble { + /// Parse the start of the Firehose data + pub fn parse_firehose_preamble( + firehose_input_data: &[u8], + ) -> nom::IResult<&[u8], FirehosePreamble> { + let mut firehose_data = FirehosePreamble { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + first_number_proc_id: 0, + second_number_proc_id: 0, + collapsed: 0, + unknown: Vec::new(), + public_data_size: 0, + private_data_virtual_offset: 0, + unkonwn2: 0, + unknown3: 0, + base_continous_time: 0, + public_data: Vec::new(), + ttl: 0, + }; + + let (input, chunk_tag) = take(size_of::())(firehose_input_data)?; + let (input, chunk_sub_tag) = take(size_of::())(input)?; + let (input, chunk_data_size) = take(size_of::())(input)?; + let (input, first_number_proc_id) = take(size_of::())(input)?; + let (input, second_number_proc_id) = take(size_of::())(input)?; + let (input, ttl) = take(size_of::())(input)?; + let (input, collapsed) = take(size_of::())(input)?; + + let (input, unknown) = take(size_of::())(input)?; + + let (input, public_data_size) = take(size_of::())(input)?; + let (input, private_data_virtual_offset) = take(size_of::())(input)?; + let (input, unknown2) = take(size_of::())(input)?; + let (input, unknown3) = take(size_of::())(input)?; + let (input, base_continous_time) = take(size_of::())(input)?; + + let (_, firehose_chunk_tag) = le_u32(chunk_tag)?; + let (_, firehose_chunk_sub_tag) = le_u32(chunk_sub_tag)?; + let (_, firehose_chunk_data_size) = le_u64(chunk_data_size)?; + let (_, firehose_first_proc_id) = le_u64(first_number_proc_id)?; + let (_, firehose_second_proc_id) = le_u32(second_number_proc_id)?; + let (_, firehose_collapsed) = le_u8(collapsed)?; + let (_, firehose_ttl) = le_u8(ttl)?; + + let (_, firehose_public_data_size) = le_u16(public_data_size)?; + let (_, firehose_private_data_virtual_offset) = le_u16(private_data_virtual_offset)?; + let (_, firehose_unknown2) = le_u16(unknown2)?; + let (_, firehose_unknown3) = le_u16(unknown3)?; + let (_, firehose_base_continous_time) = le_u64(base_continous_time)?; + + firehose_data.chunk_tag = firehose_chunk_tag; + firehose_data.chunk_sub_tag = firehose_chunk_sub_tag; + firehose_data.chunk_data_size = firehose_chunk_data_size; + firehose_data.first_number_proc_id = firehose_first_proc_id; + firehose_data.second_number_proc_id = firehose_second_proc_id; + firehose_data.collapsed = firehose_collapsed; + firehose_data.ttl = firehose_ttl; + + firehose_data.unknown = unknown.to_vec(); + + firehose_data.public_data_size = firehose_public_data_size; + firehose_data.private_data_virtual_offset = firehose_private_data_virtual_offset; + firehose_data.unkonwn2 = firehose_unknown2; + firehose_data.unknown3 = firehose_unknown3; + firehose_data.base_continous_time = firehose_base_continous_time; + + // firehose_public_data_size includes the 16 bytes before the public data offset + let public_data_size_offset = 16; + let (mut input, mut public_data) = + take(firehose_public_data_size - public_data_size_offset)(input)?; + + let log_types = vec![0x2, 0x6, 0x4, 0x7, 0x3]; + + // Go through all the public data associated with log Firehose entry + while !public_data.is_empty() { + let (firehose_input, firehose_public_data) = + FirehosePreamble::parse_firehose(public_data)?; + public_data = firehose_input; + if !log_types.contains(&firehose_public_data.unknown_log_activity_type) { + break; + } + firehose_data.public_data.push(firehose_public_data); + } + + // If there is private data, go through and update any logs that have private data items + if firehose_private_data_virtual_offset != 0x1000 { + debug!("[macos-unifiedlogs] Parsing Private Firehose Data"); + // nom any padding + let (mut private_input, _) = take_while(|b: u8| b == 0)(input)?; + + // if we nom the rest of the data (all zeros) then the private data is actually zeros + // Or if the firehose data is collapsed, then there was no padding + if private_input.is_empty() || firehose_data.collapsed == 1 { + private_input = input; + } + + for data in &mut firehose_data.public_data { + // Only non-activity firehose entries appears to have private strings + if data.firehose_non_activity.private_strings_size == 0 { + continue; + } + // Get the start of private string data + let string_offset = data.firehose_non_activity.private_strings_offset + - firehose_private_data_virtual_offset; + + let (private_string_start, _) = take(string_offset)(private_input)?; + let (_, _) = + FirehosePreamble::parse_private_data(private_string_start, &mut data.message)?; + } + input = private_input; + } + Ok((input, firehose_data)) + } + + /// Collect all the Firehose items (log message entries) in the log entry (chunk) + pub fn collect_items<'a>( + data: &'a [u8], + firehose_number_items: &u8, + firehose_flags: &u16, + ) -> nom::IResult<&'a [u8], FirehoseItemData> { + /* + Firehose Items are message types related to the log entry (chunk). There appear to be four (4) types: + strings, numbers, objects, precision + */ + let mut item_count: u8 = 0; + let mut items_data: Vec = Vec::new(); + + let mut firehose_input = data; + let mut firehose_item_data = FirehoseItemData { + item_info: Vec::new(), + backtrace_strings: Vec::new(), + }; + + // Firehose number item values + let number_item_type: Vec = vec![0x0, 0x2]; + // Dynamic precision item types? + let precision_items = [0x10, 0x12]; + // Likely realted to private string. Seen only "" values + let sensitive_items = [0x45]; + let object_items = [0x40, 0x42]; + + while &item_count < firehose_number_items { + // Get non-number values first since the values are at the end of the of the log (chunk) entry data + let (item_value_input, mut item) = + FirehosePreamble::get_firehose_items(firehose_input)?; + firehose_input = item_value_input; + + // Precision items just contain the length for the actual item + // Ex: %*s + if precision_items.contains(&item.item_type) { + items_data.push(item); + item_count += 1; + continue; + } + + // Firehose number item values immediately follow the item type + if number_item_type.contains(&item.item_type) { + let (item_value_input, message_number) = + FirehosePreamble::parse_item_number(firehose_input, u16::from(item.item_size))?; + + item.message_strings = format!("{}", message_number); + firehose_input = item_value_input; + item_count += 1; + items_data.push(item); + continue; + } + + // A message size of 0 and is an object type is "(null)" + if item.message_string_size == 0 && object_items.contains(&item.item_type) { + item.message_strings = String::from("(null)"); + } + items_data.push(item); + item_count += 1; + } + + // Backtrace data appears before Firehose item strings + // It only exists if log entry has_context_data flag set + // Backtrace data can also exist in Oversize log entries. However, Oversize entries do not have has_context_data flags. Instead we check for possible signature + let has_context_data: u16 = 0x1000; + let backtrace_signature_size: usize = 3; + + if (firehose_flags & has_context_data) != 0 { + debug!("[macos-unifiedlogs] Identified Backtrace data in Firehose log chunk"); + let (backtrace_input, backtrace_data) = + FirehosePreamble::get_backtrace_data(firehose_input)?; + firehose_input = backtrace_input; + firehose_item_data.backtrace_strings = backtrace_data; + } else if firehose_input.len() > backtrace_signature_size { + let backtrace_signature = [1, 0, 18]; + let (_, backtrace_sig) = take(backtrace_signature_size)(firehose_input)?; + if backtrace_signature == backtrace_sig { + let (backtrace_input, backtrace_data) = + FirehosePreamble::get_backtrace_data(firehose_input)?; + firehose_input = backtrace_input; + firehose_item_data.backtrace_strings = backtrace_data; + } + } + + let private_strings: Vec = vec![0x21, 0x25, 0x35, 0x31, 0x41]; + let private_number = 0x1; + // Now at the end of firehose item types. + // Remaining data (if any) contains strings for the string item types + let string_item: Vec = vec![0x20, 0x22, 0x40, 0x42, 0x30, 0x31, 0x32, 0xf2]; + + for item in &mut items_data { + // We already got number items above since the values immediantly follow the number type + if number_item_type.contains(&item.item_type) { + continue; + } + + // Check if item type is a private string. This is used for privacy related data + if private_strings.contains(&item.item_type) + || sensitive_items.contains(&item.item_type) + { + item.message_strings = String::from(""); + continue; + } + + if item.item_type == private_number { + continue; + } + + // We already got item precision info above + if precision_items.contains(&item.item_type) { + continue; + } + + if item.message_string_size == 0 && !item.message_strings.is_empty() { + continue; + } + + if firehose_input.is_empty() { + break; + } + if string_item.contains(&item.item_type) { + let (item_value_input, message_string) = FirehosePreamble::parse_item_string( + firehose_input, + &item.item_type, + item.message_string_size, + )?; + firehose_input = item_value_input; + item.message_strings = message_string; + } else { + error!( + "[macos-unifiedlogs] Unknown Firehose item: {}", + &item.item_type + ); + debug!("[macos-unifiedlogs] Firehose item data: {:?}", data); + } + } + + // We now have all of the firehose items and the data + // Go through and append to vec + for item in items_data { + let item_info = FirehoseItemInfo { + message_strings: item.message_strings, + item_type: item.item_type, + item_size: item.message_string_size, + }; + firehose_item_data.item_info.push(item_info); + } + Ok((firehose_input, firehose_item_data)) + } + + /// Parse any private firehose data and update any firehose items that use private data + pub fn parse_private_data<'a>( + data: &'a [u8], + firehose_item_data: &mut FirehoseItemData, + ) -> nom::IResult<&'a [u8], ()> { + let private_strings: Vec = vec![0x21, 0x25, 0x41, 0x35, 0x31]; + let private_number = 0x1; + + let mut private_string_start = data; + // Go through all firehose items, for each private item entry get the private value + for firehose_info in &mut firehose_item_data.item_info { + if private_strings.contains(&firehose_info.item_type) { + // Base64 encode arbitrary data. Need to further parse them based on base string formatters + if firehose_info.item_type == private_strings[3] + || firehose_info.item_type == private_strings[4] + { + if private_string_start.len() < firehose_info.item_size as usize { + let (private_data, pointer_object) = + take(private_string_start.len())(private_string_start)?; + private_string_start = private_data; + firehose_info.message_strings = base64::encode(pointer_object); + + continue; + } + + let (private_data, pointer_object) = + take(firehose_info.item_size)(private_string_start)?; + private_string_start = private_data; + firehose_info.message_strings = base64::encode(pointer_object); + continue; + } + + let (private_data, private_string) = + extract_string_size(private_string_start, u64::from(firehose_info.item_size))?; + + private_string_start = private_data; + firehose_info.message_strings = private_string; + } else if firehose_info.item_type == private_number { + let (private_data, private_string) = FirehosePreamble::parse_item_number( + private_string_start, + firehose_info.item_size, + )?; + private_string_start = private_data; + firehose_info.message_strings = format!("{}", private_string); + } + } + Ok((private_string_start, ())) + } + + // Parse all the different types of Firehose data (activity, non-activity, loss, trace, signpost) + fn parse_firehose(data: &[u8]) -> nom::IResult<&[u8], Firehose> { + let mut firehose_results = Firehose { + unknown_log_activity_type: 0, + unknown_log_type: 0, + flags: 0, + format_string_location: 0, + thread_id: 0, + continous_time_delta: 0, + continous_time_delta_upper: 0, + data_size: 0, + firehose_activity: FirehoseActivity { + unknown_activity_id: 0, + unknown_sentinal: 0, + pid: 0, + unknown_activity_id_2: 0, + unknown_sentinal_2: 0, + unknown_activity_id_3: 0, + unknown_sentinal_3: 0, + unknown_message_string_ref: 0, + unknown_pc_id: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + }, + firehose_non_activity: FirehoseNonActivity { + unknown_activity_id: 0, + unknown_sentinal: 0, + private_strings_offset: 0, + private_strings_size: 0, + unknown_message_string_ref: 0, + subsystem_value: 0, + ttl_value: 0, + data_ref_value: 0, + unknown_pc_id: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + }, + firehose_loss: FirehoseLoss { + start_time: 0, + end_time: 0, + count: 0, + }, + firehose_trace: FirehoseTrace { + unknown_pc_id: 0, + message_value: 0, + unknown_data: Vec::new(), + }, + firehose_signpost: FirehoseSignpost { + unknown_pc_id: 0, + unknown_activity_id: 0, + unknown_sentinel: 0, + subsystem: 0, + signpost_id: 0, + signpost_name: 0, + private_strings_offset: 0, + private_strings_size: 0, + ttl_value: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + data_ref_value: 0, + }, + unknown_item: 0, + number_items: 0, + message: FirehoseItemData { + item_info: Vec::new(), + backtrace_strings: Vec::new(), + }, + }; + + let (input, unknown_log_activity_type) = take(size_of::())(data)?; + let (input, unknown_log_type) = take(size_of::())(input)?; + let (input, flags) = take(size_of::())(input)?; + let (input, format_string_location) = take(size_of::())(input)?; + + let (input, thread_id) = take(size_of::())(input)?; + + let (input, continous_time_delta) = take(size_of::())(input)?; + let (input, continous_time_delta_upper) = take(size_of::())(input)?; + let (input, data_size) = take(size_of::())(input)?; + + let (_, firehose_unknown_log_activity_type) = le_u8(unknown_log_activity_type)?; + let (_, firehose_unknown_log_type) = le_u8(unknown_log_type)?; + let (_, firehose_flags) = le_u16(flags)?; + let (_, firehose_format_string_location) = le_u32(format_string_location)?; + let (_, firehose_continous_delta_upper) = le_u16(continous_time_delta_upper)?; + let (_, firehose_continous_delta) = le_u32(continous_time_delta)?; + + let (_, firehose_thread_id) = le_u64(thread_id)?; + let (_, firehose_data_size) = le_u16(data_size)?; + + firehose_results.unknown_log_activity_type = firehose_unknown_log_activity_type; + firehose_results.unknown_log_type = firehose_unknown_log_type; + firehose_results.flags = firehose_flags; + firehose_results.format_string_location = firehose_format_string_location; + firehose_results.thread_id = firehose_thread_id; + firehose_results.continous_time_delta_upper = firehose_continous_delta_upper; + firehose_results.continous_time_delta = firehose_continous_delta; + firehose_results.data_size = firehose_data_size; + + let (input, mut firehose_input) = take(firehose_data_size)(input)?; + + // Log activity type (unknown_log_activity_type) + let activity: u8 = 0x2; + let signpost: u8 = 0x6; + let nonactivity: u8 = 0x4; + let loss: u8 = 0x7; + let trace: u8 = 0x3; + + // Unknown types + let unknown_remenant_data = 0x0; // 0x0 appears to be remenant data or garbage data (log command does not parse it either) + + if firehose_unknown_log_activity_type == activity { + let (activity_data, activity) = FirehoseActivity::parse_activity( + firehose_input, + &firehose_flags, + &firehose_unknown_log_type, + )?; + firehose_input = activity_data; + firehose_results.firehose_activity = activity; + } else if firehose_unknown_log_activity_type == nonactivity { + let (non_activity_data, non_activity) = + FirehoseNonActivity::parse_non_activity(firehose_input, &firehose_flags)?; + firehose_input = non_activity_data; + firehose_results.firehose_non_activity = non_activity; + } else if firehose_unknown_log_activity_type == signpost { + let (process_data, firehose_signpost) = + FirehoseSignpost::parse_signpost(firehose_input, &firehose_flags)?; + firehose_input = process_data; + firehose_results.firehose_signpost = firehose_signpost; + } else if firehose_unknown_log_activity_type == loss { + let (loss_data, firehose_loss) = FirehoseLoss::parse_firehose_loss(firehose_input)?; + firehose_results.firehose_loss = firehose_loss; + firehose_input = loss_data; + } else if firehose_unknown_log_activity_type == trace { + let (trace_data, firehose_trace) = FirehoseTrace::parse_firehose_trace(firehose_input)?; + firehose_results.firehose_trace = firehose_trace; + firehose_input = trace_data; + + // Trace entries are odd, they dont follow the format of other log entries + firehose_results.message = FirehoseTrace::get_trace_message_string( + firehose_results.firehose_trace.message_value, + ); + } else if firehose_unknown_log_activity_type == unknown_remenant_data { + return Ok((input, firehose_results)); + } else { + warn!( + "[macos-unifiedlogs] Unknown log activity type: {} - {} bytes left", + firehose_unknown_log_activity_type, + input.len() + ); + debug!("[macos-unifiedlogs] Firehose data: {:?}", data); + return Ok((input, firehose_results)); + } + + let minimum_item_size = 6; + if firehose_input.len() < minimum_item_size { + let padding_size = padding_size(firehose_results.data_size.into()); + let (input, _) = take(padding_size)(input)?; + return Ok((input, firehose_results)); + } + + let (firehose_input, unknown_item) = take(size_of::())(firehose_input)?; + let (firehose_input, number_items) = take(size_of::())(firehose_input)?; + + let (_, firehose_unknown_item) = le_u8(unknown_item)?; + let (_, firehose_number_items) = le_u8(number_items)?; + + firehose_results.unknown_item = firehose_unknown_item; + firehose_results.number_items = firehose_number_items; + + let (_, firehose_item_data) = FirehosePreamble::collect_items( + firehose_input, + &firehose_number_items, + &firehose_flags, + )?; + + firehose_results.message = firehose_item_data; + + let padding_data = padding_size(firehose_data_size.into()); + let (input, _) = take(padding_data)(input)?; + Ok((input, firehose_results)) + } + + // Parse Backtrace data for log entry (chunk). This only exists if has_context_data flag is set + fn get_backtrace_data(data: &[u8]) -> nom::IResult<&[u8], Vec> { + let (input, _unknown_data) = take(size_of::())(data)?; + let (input, _unknown_data2) = take(size_of::())(input)?; + let (input, number_uuids) = take(size_of::())(input)?; + let (mut input, number_offsets) = take(size_of::())(input)?; + + let (_, backtrace_uuid_count) = le_u8(number_uuids)?; + let (_, backtrace_offsets_count) = le_u16(number_offsets)?; + + let mut uuid_vec: Vec = Vec::new(); + let mut count = 0; + while count < backtrace_uuid_count { + let (uuid_input, uuid_data) = take(size_of::())(input)?; + let (_, uuid) = be_u128(uuid_data)?; + uuid_vec.push(format!("{:X}", uuid)); + input = uuid_input; + count += 1; + } + count = 0; + let mut offsets_vec: Vec = Vec::new(); + while (u16::from(count)) < backtrace_offsets_count { + let (offset_input, offset) = take(size_of::())(input)?; + let (_, backtrace_offsets) = le_u32(offset)?; + offsets_vec.push(backtrace_offsets); + input = offset_input; + count += 1; + } + + let mut backtrace_data: Vec = Vec::new(); + count = 0; + while (u16::from(count)) < backtrace_offsets_count { + let (index_input, index) = take(size_of::())(input)?; + let (_, uuid_index) = le_u8(index)?; + if (uuid_index as usize) < uuid_vec.len() { + backtrace_data.push(format!( + "{:?} +0x{:?}", + uuid_vec[uuid_index as usize], offsets_vec[count as usize] + )); + } else { + backtrace_data.push(format!( + "00000000-0000-0000-0000-000000000000 +0x{:?}", + offsets_vec[count as usize] + )); + } + input = index_input; + count += 1; + } + let padding_size = padding_size_four(u64::from(backtrace_offsets_count)); + let (backtrace_input, _) = take(padding_size)(input)?; + input = backtrace_input; + Ok((input, backtrace_data)) + } + + // Get the strings, precision, and private (sensitive) firehose message items + fn get_firehose_items(data: &[u8]) -> nom::IResult<&[u8], FirehoseItemType> { + let (firehose_input, item_type) = take(size_of::())(data)?; + let (mut firehose_input, item_size) = take(size_of::())(firehose_input)?; + let (_, item_type) = le_u8(item_type)?; + let (_, item_size) = le_u8(item_size)?; + + let mut item = FirehoseItemType { + item_type, + item_size, + offset: 0, + message_string_size: 0, + message_strings: String::new(), + backtrace_strings: Vec::new(), + }; + + // Firehose string item values + let string_item: Vec = vec![ + 0x20, 0x21, 0x22, 0x25, 0x40, 0x41, 0x42, 0x30, 0x31, 0x32, 0xf2, 0x35, + ]; + let private_number = 0x1; + // String and private number items metadata is 4 bytes + // first two (2) bytes point to the offset of the string data + // last two (2) bytes is the size of of string + if string_item.contains(&item.item_type) || item.item_type == private_number { + // The offset is relative to start of string data (after all other firehose items) + let (input, offset) = take(size_of::())(firehose_input)?; + let (_, message_offset) = le_u16(offset)?; + let (input, message_data_size) = take(size_of::())(input)?; + let (_, message_size) = le_u16(message_data_size)?; + + item.offset = message_offset; + item.message_string_size = message_size; + firehose_input = input; + } + + // Precision items just contain the length for the actual item. Ex: %*s + let precision_items = [0x10, 0x12]; + if precision_items.contains(&item.item_type) { + let (input, _) = take(item.item_size)(firehose_input)?; + firehose_input = input; + } + let sensitive_items = [0x45]; + if sensitive_items.contains(&item.item_type) { + let (input, offset) = take(size_of::())(firehose_input)?; + let (_, message_offset) = le_u16(offset)?; + let (input, message_data_size) = take(size_of::())(input)?; + let (_, message_size) = le_u16(message_data_size)?; + + item.offset = message_offset; + item.message_string_size = message_size; + firehose_input = input; + } + Ok((firehose_input, item)) + } + + // Parse the item string + fn parse_item_string<'a>( + data: &'a [u8], + item_type: &u8, + message_size: u16, + ) -> nom::IResult<&'a [u8], String> { + // If message item size is greater than the remaining data, just use the rest of the data + if message_size as usize > data.len() { + return extract_string_size(data, data.len() as u64); + } + + let (input, message_data) = take(message_size)(data)?; + let arbitrary: Vec = vec![0x30, 0x31, 0x32]; + // 0x30, 0x31, and 0x32 represent arbitrary data, need to be decoded again + // Ex: name: %{private, mask.hash, mdnsresponder:domain_name}.*P, type: A, rdata: %{private, mask.hash, network:in_addr}.4P + if arbitrary.contains(item_type) { + return Ok((input, base64::encode(message_data))); + } + + let base64_raw_bytes: u8 = 0xf2; + if item_type == &base64_raw_bytes { + return Ok((input, base64::encode(message_data))); + } + + let (_, message_string) = extract_string_size(message_data, u64::from(message_size))?; + Ok((input, message_string)) + } + + // Parse the Firehose item number + fn parse_item_number(data: &[u8], item_size: u16) -> nom::IResult<&[u8], i64> { + let (input, message_data) = take(item_size)(data)?; + let message_number = match item_size { + 4 => { + let (_, message) = le_i32(message_data)?; + i64::from(message) + } + 2 => { + let (_, message) = le_i16(message_data)?; + i64::from(message) + } + 8 => { + let (_, message) = le_i64(message_data)?; + message + } + 1 => { + let (_, message) = le_i8(message_data)?; + i64::from(message) + } + _ => { + warn!( + "[macos-unifiedlogs] Unknown number size support: {:?}", + item_size + ); + debug!("[macos-unifiedlogs] Item data: {:?}", data); + -9999 + } + }; + Ok((input, message_number)) + } +} + +#[cfg(test)] +mod tests { + use std::{fs::File, io::Read, path::PathBuf}; + + use super::{FirehoseItemData, FirehoseItemInfo, FirehosePreamble}; + + #[test] + fn test_parse_firehose_preamble() { + let test_firehose_data = [ + 1, 96, 0, 0, 0, 0, 0, 0, 192, 15, 0, 0, 0, 0, 0, 0, 227, 1, 0, 0, 0, 0, 0, 0, 99, 4, 0, + 0, 0, 0, 0, 0, 176, 15, 0, 16, 0, 0, 0, 3, 153, 49, 153, 58, 209, 3, 0, 0, 4, 0, 4, 2, + 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 49, 0, 96, 156, 185, 7, + 23, 1, 34, 1, 66, 4, 0, 0, 35, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, + 116, 97, 116, 101, 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 52, 54, 58, 32, 101, + 110, 116, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 73, 211, 0, + 0, 0, 0, 0, 0, 170, 14, 10, 0, 16, 0, 63, 0, 96, 156, 185, 7, 23, 1, 34, 1, 66, 4, 0, + 0, 49, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, 116, 97, 116, 101, 70, 111, + 114, 85, 115, 101, 114, 58, 49, 50, 54, 54, 58, 32, 83, 65, 58, 32, 99, 117, 114, 114, + 101, 110, 116, 83, 116, 97, 116, 101, 58, 32, 50, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, + 186, 14, 0, 0, 0, 0, 0, 0, 241, 76, 14, 0, 16, 0, 63, 0, 96, 156, 185, 7, 23, 1, 34, 1, + 66, 4, 0, 0, 49, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, 116, 97, 116, + 101, 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 54, 54, 58, 32, 83, 65, 58, 32, 99, + 117, 114, 114, 101, 110, 116, 83, 116, 97, 116, 101, 58, 32, 50, 0, 0, 4, 0, 2, 2, 32, + 127, 50, 0, 186, 14, 0, 0, 0, 0, 0, 0, 243, 97, 14, 0, 16, 0, 8, 0, 202, 201, 13, 0, + 186, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 204, 195, 14, 0, + 16, 0, 48, 0, 96, 156, 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 34, 0, 83, 65, 67, 83, 104, + 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, 58, + 52, 57, 54, 58, 32, 101, 110, 116, 101, 114, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, + 0, 0, 0, 0, 0, 0, 187, 247, 23, 0, 16, 0, 74, 0, 96, 156, 185, 7, 24, 1, 34, 1, 66, 4, + 0, 0, 60, 0, 83, 65, 67, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, + 104, 111, 119, 105, 110, 103, 58, 53, 48, 53, 58, 32, 101, 120, 105, 116, 58, 32, 105, + 115, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, + 110, 103, 32, 61, 32, 48, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 2, 32, 127, 50, 0, 186, 14, 0, + 0, 0, 0, 0, 0, 113, 161, 24, 0, 16, 0, 8, 0, 196, 47, 42, 0, 102, 0, 0, 0, 4, 0, 4, 2, + 96, 182, 161, 3, 91, 230, 0, 0, 0, 0, 0, 0, 124, 41, 20, 80, 150, 0, 28, 0, 11, 206, + 107, 3, 54, 0, 0, 2, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 4, 2, 144, 182, 161, 3, 186, 14, 0, 0, 0, 0, 0, 0, 169, 201, 20, 80, 150, + 0, 28, 0, 104, 207, 107, 3, 54, 0, 0, 2, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, + 172, 1, 129, 52, 164, 0, 49, 0, 96, 156, 185, 7, 23, 1, 34, 1, 66, 4, 0, 0, 35, 0, 83, + 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, 116, 97, 116, 101, 70, 111, 114, 85, 115, + 101, 114, 58, 49, 50, 52, 54, 58, 32, 101, 110, 116, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 4, 2, 112, 174, 185, 7, 87, 232, 0, 0, 0, 0, 0, 0, 177, 70, 129, 52, 164, 0, 49, + 0, 96, 156, 185, 7, 23, 1, 34, 1, 66, 4, 0, 0, 35, 0, 83, 65, 83, 83, 101, 115, 115, + 105, 111, 110, 83, 116, 97, 116, 101, 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 52, + 54, 58, 32, 101, 110, 116, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, + 7, 186, 14, 0, 0, 0, 0, 0, 0, 108, 29, 135, 52, 164, 0, 63, 0, 96, 156, 185, 7, 23, 1, + 34, 1, 66, 4, 0, 0, 49, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, 116, 97, + 116, 101, 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 54, 54, 58, 32, 83, 65, 58, 32, + 99, 117, 114, 114, 101, 110, 116, 83, 116, 97, 116, 101, 58, 32, 51, 0, 0, 4, 0, 2, 2, + 0, 127, 50, 0, 186, 14, 0, 0, 0, 0, 0, 0, 39, 46, 135, 52, 164, 0, 8, 0, 202, 201, 13, + 0, 186, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 214, 129, + 135, 52, 164, 0, 48, 0, 96, 156, 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 34, 0, 83, 65, 67, + 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, + 103, 58, 52, 57, 54, 58, 32, 101, 110, 116, 101, 114, 0, 4, 0, 4, 2, 112, 174, 185, 7, + 87, 232, 0, 0, 0, 0, 0, 0, 129, 190, 135, 52, 164, 0, 63, 0, 96, 156, 185, 7, 23, 1, + 34, 1, 66, 4, 0, 0, 49, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, 116, 97, + 116, 101, 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 54, 54, 58, 32, 83, 65, 58, 32, + 99, 117, 114, 114, 101, 110, 116, 83, 116, 97, 116, 101, 58, 32, 51, 0, 0, 4, 0, 4, 2, + 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 111, 24, 141, 52, 164, 0, 74, 0, 96, 156, + 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 60, 0, 83, 65, 67, 83, 104, 105, 101, 108, 100, 87, + 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, 58, 53, 48, 53, 58, 32, 101, + 120, 105, 116, 58, 32, 105, 115, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, + 119, 83, 104, 111, 119, 105, 110, 103, 32, 61, 32, 48, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 2, + 0, 127, 50, 0, 186, 14, 0, 0, 0, 0, 0, 0, 218, 54, 117, 55, 164, 0, 8, 0, 196, 47, 42, + 0, 102, 0, 0, 0, 4, 0, 4, 0, 96, 229, 48, 2, 104, 233, 0, 0, 0, 0, 0, 0, 250, 34, 131, + 39, 171, 0, 16, 0, 98, 140, 31, 2, 0, 1, 0, 8, 150, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, + 128, 228, 48, 2, 104, 233, 0, 0, 0, 0, 0, 0, 100, 244, 131, 39, 171, 0, 30, 0, 238, 39, + 223, 1, 35, 4, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 150, 0, 0, 0, 33, 4, 0, 0, 0, + 0, 0, 0, 4, 0, 4, 0, 192, 228, 48, 2, 104, 233, 0, 0, 0, 0, 0, 0, 156, 248, 131, 39, + 171, 0, 24, 0, 248, 40, 223, 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 150, 0, + 0, 0, 4, 0, 4, 2, 96, 182, 161, 3, 104, 233, 0, 0, 0, 0, 0, 0, 97, 179, 140, 39, 171, + 0, 28, 0, 11, 206, 107, 3, 54, 0, 0, 2, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 144, 182, 161, 3, 186, 14, 0, 0, 0, 0, 0, 0, 226, + 13, 142, 39, 171, 0, 28, 0, 104, 207, 107, 3, 54, 0, 0, 2, 0, 8, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 96, 182, 161, 3, 99, 233, 0, + 0, 0, 0, 0, 0, 233, 233, 149, 39, 171, 0, 28, 0, 11, 206, 107, 3, 54, 0, 0, 2, 0, 8, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 96, 229, 48, + 2, 202, 232, 0, 0, 0, 0, 0, 0, 51, 189, 188, 39, 171, 0, 16, 0, 98, 140, 31, 2, 0, 1, + 0, 8, 149, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 128, 228, 48, 2, 104, 233, 0, 0, 0, 0, 0, + 0, 123, 62, 189, 39, 171, 0, 30, 0, 238, 39, 223, 1, 35, 4, 0, 4, 0, 0, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 4, 149, 0, 0, 0, 33, 4, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 192, 228, 48, 2, 104, + 233, 0, 0, 0, 0, 0, 0, 98, 67, 189, 39, 171, 0, 24, 0, 248, 40, 223, 1, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 149, 0, 0, 0, 4, 0, 4, 2, 144, 144, 243, 18, 99, 233, + 0, 0, 0, 0, 0, 0, 222, 140, 189, 39, 171, 0, 189, 0, 136, 175, 234, 18, 177, 0, 35, 10, + 32, 4, 0, 0, 38, 0, 0, 8, 48, 29, 118, 0, 0, 96, 0, 0, 66, 4, 38, 0, 14, 0, 66, 4, 52, + 0, 28, 0, 66, 4, 80, 0, 31, 0, 66, 4, 0, 0, 0, 0, 65, 4, 0, 0, 0, 0, 65, 4, 0, 0, 0, 0, + 66, 4, 111, 0, 3, 0, 66, 4, 114, 0, 3, 0, 65, 86, 70, 105, 103, 82, 111, 117, 116, 105, + 110, 103, 67, 111, 110, 116, 101, 120, 116, 82, 111, 117, 116, 101, 67, 111, 110, 102, + 105, 103, 85, 112, 100, 97, 116, 101, 100, 0, 52, 56, 52, 50, 50, 50, 51, 51, 53, 50, + 50, 50, 54, 0, 99, 111, 110, 102, 105, 103, 85, 112, 100, 97, 116, 101, 82, 101, 97, + 115, 111, 110, 69, 110, 100, 101, 100, 78, 111, 111, 112, 0, 114, 111, 117, 116, 105, + 110, 103, 77, 97, 110, 97, 103, 101, 114, 95, 104, 97, 110, 100, 108, 101, 82, 111, + 117, 116, 101, 65, 119, 97, 121, 0, 78, 79, 0, 78, 79, 0, 0, 0, 0, 4, 0, 4, 2, 144, + 182, 161, 3, 186, 14, 0, 0, 0, 0, 0, 0, 213, 193, 218, 39, 171, 0, 28, 0, 104, 207, + 107, 3, 54, 0, 0, 2, 0, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 4, 2, 112, 69, 76, 12, 104, 233, 0, 0, 0, 0, 0, 0, 17, 94, 168, 40, 171, 0, + 30, 0, 22, 181, 70, 12, 22, 1, 35, 2, 65, 4, 0, 0, 0, 0, 64, 4, 0, 0, 10, 0, 48, 46, + 55, 48, 52, 49, 48, 49, 54, 0, 0, 0, 4, 0, 4, 2, 96, 182, 161, 3, 104, 233, 0, 0, 0, 0, + 0, 0, 219, 50, 32, 232, 177, 0, 28, 0, 11, 206, 107, 3, 54, 0, 0, 2, 0, 8, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 144, 182, 161, 3, + 186, 14, 0, 0, 0, 0, 0, 0, 29, 176, 32, 232, 177, 0, 28, 0, 104, 207, 107, 3, 54, 0, 0, + 2, 0, 8, 10, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, + 144, 144, 243, 18, 104, 233, 0, 0, 0, 0, 0, 0, 67, 134, 39, 232, 177, 0, 189, 0, 136, + 175, 234, 18, 177, 0, 35, 10, 32, 4, 0, 0, 38, 0, 0, 8, 48, 29, 118, 0, 0, 96, 0, 0, + 66, 4, 38, 0, 14, 0, 66, 4, 52, 0, 28, 0, 66, 4, 80, 0, 31, 0, 66, 4, 0, 0, 0, 0, 65, + 4, 0, 0, 0, 0, 65, 4, 0, 0, 0, 0, 66, 4, 111, 0, 3, 0, 66, 4, 114, 0, 3, 0, 65, 86, 70, + 105, 103, 82, 111, 117, 116, 105, 110, 103, 67, 111, 110, 116, 101, 120, 116, 82, 111, + 117, 116, 101, 67, 111, 110, 102, 105, 103, 85, 112, 100, 97, 116, 101, 100, 0, 52, 56, + 55, 49, 50, 50, 49, 55, 52, 54, 55, 50, 56, 0, 99, 111, 110, 102, 105, 103, 85, 112, + 100, 97, 116, 101, 82, 101, 97, 115, 111, 110, 69, 110, 100, 101, 100, 78, 111, 111, + 112, 0, 114, 111, 117, 116, 105, 110, 103, 77, 97, 110, 97, 103, 101, 114, 95, 104, 97, + 110, 100, 108, 101, 82, 111, 117, 116, 101, 65, 119, 97, 121, 0, 78, 79, 0, 78, 79, 0, + 0, 0, 0, 4, 0, 4, 2, 96, 182, 161, 3, 129, 233, 0, 0, 0, 0, 0, 0, 255, 163, 136, 232, + 177, 0, 28, 0, 11, 206, 107, 3, 54, 0, 0, 2, 0, 8, 11, 0, 0, 0, 0, 0, 0, 0, 0, 8, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 144, 182, 161, 3, 186, 14, 0, 0, 0, 0, 0, 0, + 12, 137, 137, 232, 177, 0, 28, 0, 104, 207, 107, 3, 54, 0, 0, 2, 0, 8, 11, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 112, 69, 76, 12, 129, + 233, 0, 0, 0, 0, 0, 0, 98, 9, 164, 232, 177, 0, 30, 0, 22, 181, 70, 12, 22, 1, 35, 2, + 65, 4, 0, 0, 0, 0, 64, 4, 0, 0, 10, 0, 48, 46, 54, 51, 53, 55, 52, 50, 50, 0, 0, 0, 4, + 16, 4, 2, 220, 230, 161, 3, 186, 14, 0, 0, 0, 0, 0, 0, 76, 242, 207, 232, 177, 0, 14, + 0, 88, 179, 32, 3, 51, 0, 35, 1, 65, 4, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 176, 229, 48, 2, + 129, 233, 0, 0, 0, 0, 0, 0, 228, 147, 135, 235, 177, 0, 16, 0, 131, 142, 31, 2, 0, 1, + 0, 8, 150, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 240, 228, 48, 2, 129, 233, 0, 0, 0, 0, 0, + 0, 146, 215, 135, 235, 177, 0, 30, 0, 129, 44, 223, 1, 35, 4, 0, 4, 0, 0, 0, 0, 0, 4, + 1, 0, 0, 0, 0, 4, 150, 0, 0, 0, 33, 4, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 48, 229, 48, 2, + 129, 233, 0, 0, 0, 0, 0, 0, 0, 217, 135, 235, 177, 0, 24, 0, 127, 45, 223, 1, 0, 3, 0, + 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 150, 0, 0, 0, 4, 0, 4, 0, 176, 229, 48, 2, 129, + 233, 0, 0, 0, 0, 0, 0, 151, 240, 137, 235, 177, 0, 16, 0, 131, 142, 31, 2, 0, 1, 0, 8, + 149, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 240, 228, 48, 2, 129, 233, 0, 0, 0, 0, 0, 0, 7, + 33, 138, 235, 177, 0, 30, 0, 129, 44, 223, 1, 35, 4, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, + 0, 0, 4, 149, 0, 0, 0, 33, 4, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 48, 229, 48, 2, 129, 233, + 0, 0, 0, 0, 0, 0, 246, 33, 138, 235, 177, 0, 24, 0, 127, 45, 223, 1, 0, 3, 0, 4, 0, 0, + 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 149, 0, 0, 0, 4, 0, 2, 2, 112, 98, 50, 0, 186, 14, 0, 0, + 0, 0, 0, 0, 44, 130, 197, 237, 177, 0, 8, 0, 180, 56, 9, 0, 186, 0, 0, 0, 4, 0, 4, 2, + 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 138, 169, 207, 237, 177, 0, 48, 0, 96, + 156, 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 34, 0, 83, 65, 67, 83, 104, 105, 101, 108, 100, + 87, 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, 58, 52, 57, 54, 58, 32, + 101, 110, 116, 101, 114, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, + 105, 27, 216, 237, 177, 0, 74, 0, 96, 156, 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 60, 0, + 83, 65, 67, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, + 119, 105, 110, 103, 58, 53, 48, 53, 58, 32, 101, 120, 105, 116, 58, 32, 105, 115, 83, + 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, + 32, 61, 32, 48, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, + 0, 0, 79, 252, 217, 237, 177, 0, 48, 0, 96, 156, 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 34, + 0, 83, 65, 67, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, + 119, 105, 110, 103, 58, 52, 57, 54, 58, 32, 101, 110, 116, 101, 114, 0, 4, 0, 4, 2, + 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 67, 249, 223, 237, 177, 0, 74, 0, 96, 156, + 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 60, 0, 83, 65, 67, 83, 104, 105, 101, 108, 100, 87, + 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, 58, 53, 48, 53, 58, 32, 101, + 120, 105, 116, 58, 32, 105, 115, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, + 119, 83, 104, 111, 119, 105, 110, 103, 32, 61, 32, 48, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 2, + 80, 98, 50, 0, 186, 14, 0, 0, 0, 0, 0, 0, 1, 240, 28, 157, 179, 0, 8, 0, 180, 56, 9, 0, + 186, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 92, 138, 42, + 157, 179, 0, 48, 0, 96, 156, 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 34, 0, 83, 65, 67, 83, + 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, + 58, 52, 57, 54, 58, 32, 101, 110, 116, 101, 114, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, + 14, 0, 0, 0, 0, 0, 0, 0, 111, 47, 157, 179, 0, 74, 0, 96, 156, 185, 7, 24, 1, 34, 1, + 66, 4, 0, 0, 60, 0, 83, 65, 67, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, + 119, 83, 104, 111, 119, 105, 110, 103, 58, 53, 48, 53, 58, 32, 101, 120, 105, 116, 58, + 32, 105, 115, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, + 119, 105, 110, 103, 32, 61, 32, 48, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, + 186, 14, 0, 0, 0, 0, 0, 0, 92, 146, 49, 157, 179, 0, 48, 0, 96, 156, 185, 7, 24, 1, 34, + 1, 66, 4, 0, 0, 34, 0, 83, 65, 67, 83, 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, + 119, 83, 104, 111, 119, 105, 110, 103, 58, 52, 57, 54, 58, 32, 101, 110, 116, 101, 114, + 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 48, 165, 53, 157, 179, 0, + 74, 0, 96, 156, 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 60, 0, 83, 65, 67, 83, 104, 105, + 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, 58, 53, + 48, 53, 58, 32, 101, 120, 105, 116, 58, 32, 105, 115, 83, 104, 105, 101, 108, 100, 87, + 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, 32, 61, 32, 48, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 236, 184, 97, 157, + 179, 0, 49, 0, 96, 156, 185, 7, 23, 1, 34, 1, 66, 4, 0, 0, 35, 0, 83, 65, 83, 83, 101, + 115, 115, 105, 111, 110, 83, 116, 97, 116, 101, 70, 111, 114, 85, 115, 101, 114, 58, + 49, 50, 52, 54, 58, 32, 101, 110, 116, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, + 112, 174, 185, 7, 129, 233, 0, 0, 0, 0, 0, 0, 65, 208, 97, 157, 179, 0, 49, 0, 96, 156, + 185, 7, 23, 1, 34, 1, 66, 4, 0, 0, 35, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, + 83, 116, 97, 116, 101, 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 52, 54, 58, 32, + 101, 110, 116, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, + 0, 0, 0, 0, 0, 0, 186, 180, 102, 157, 179, 0, 63, 0, 96, 156, 185, 7, 23, 1, 34, 1, 66, + 4, 0, 0, 49, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, 116, 97, 116, 101, + 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 54, 54, 58, 32, 83, 65, 58, 32, 99, 117, + 114, 114, 101, 110, 116, 83, 116, 97, 116, 101, 58, 32, 50, 0, 0, 4, 0, 2, 2, 32, 127, + 50, 0, 186, 14, 0, 0, 0, 0, 0, 0, 222, 192, 102, 157, 179, 0, 8, 0, 202, 201, 13, 0, + 186, 0, 0, 0, 4, 0, 4, 2, 112, 174, 185, 7, 186, 14, 0, 0, 0, 0, 0, 0, 124, 254, 102, + 157, 179, 0, 48, 0, 96, 156, 185, 7, 24, 1, 34, 1, 66, 4, 0, 0, 34, 0, 83, 65, 67, 83, + 104, 105, 101, 108, 100, 87, 105, 110, 100, 111, 119, 83, 104, 111, 119, 105, 110, 103, + 58, 52, 57, 54, 58, 32, 101, 110, 116, 101, 114, 0, 4, 0, 4, 2, 112, 174, 185, 7, 129, + 233, 0, 0, 0, 0, 0, 0, 134, 30, 103, 157, 179, 0, 63, 0, 96, 156, 185, 7, 23, 1, 34, 1, + 66, 4, 0, 0, 49, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, 116, 97, 116, + 101, 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 54, 54, 58, 32, 83, 65, 58, 32, 99, + 117, 114, 114, 101, 110, 116, 83, 116, 97, 116, 101, 58, 32, 50, 0, 0, 1, 96, 0, 0, 0, + 0, 0, 0, 232, 15, 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 192, 1, 0, 0, 0, 0, 0, 0, + 216, 15, 0, 16, 0, 0, 0, 3, 34, 79, 194, 43, 115, 4, 0, 0, 4, 0, 45, 2, 224, 238, 31, + 18, 54, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 37, 0, 210, 250, 0, 0, 0, 0, 0, 128, + 100, 211, 25, 18, 1, 0, 2, 0, 14, 0, 34, 2, 0, 4, 135, 16, 0, 0, 34, 4, 0, 0, 5, 0, + 100, 101, 110, 121, 0, 0, 0, 0, 4, 16, 45, 2, 240, 59, 32, 18, 54, 234, 0, 0, 0, 0, 0, + 0, 63, 12, 0, 0, 16, 0, 20, 0, 210, 250, 0, 0, 0, 0, 0, 128, 79, 15, 31, 18, 1, 0, 2, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 242, 233, 0, 0, 0, 0, 0, 0, + 225, 250, 255, 255, 15, 0, 163, 0, 210, 250, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, + 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 86, 0, 66, 4, 86, 0, 15, 0, 66, 4, 101, 0, 24, 0, 120, + 112, 99, 115, 101, 114, 118, 105, 99, 101, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 67, 114, 121, 112, 116, 111, 84, 111, 107, 101, 110, 75, 105, 116, 46, 112, + 105, 118, 116, 111, 107, 101, 110, 40, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, + 109, 46, 97, 112, 112, 108, 101, 46, 99, 116, 107, 100, 40, 53, 48, 49, 41, 62, 58, 52, + 53, 50, 93, 41, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, 45, 97, + 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, + 118, 101, 78, 111, 110, 70, 111, 99, 97, 108, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 176, 15, + 32, 18, 235, 233, 0, 0, 0, 0, 0, 0, 149, 134, 234, 0, 16, 0, 16, 0, 212, 250, 0, 0, 0, + 0, 0, 128, 50, 81, 27, 18, 1, 0, 2, 0, 4, 0, 45, 2, 208, 15, 32, 18, 235, 233, 0, 0, 0, + 0, 0, 0, 43, 145, 234, 0, 16, 0, 38, 0, 212, 250, 0, 0, 0, 0, 0, 128, 194, 82, 27, 18, + 1, 0, 2, 0, 16, 0, 0, 3, 0, 4, 135, 16, 0, 0, 0, 4, 245, 1, 0, 0, 0, 4, 245, 1, 0, 0, + 0, 0, 2, 1, 44, 0, 32, 250, 31, 18, 53, 234, 0, 0, 0, 0, 0, 0, 72, 69, 236, 0, 16, 0, + 16, 0, 213, 250, 0, 0, 0, 0, 0, 128, 15, 39, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 32, 249, + 31, 18, 53, 234, 0, 0, 0, 0, 0, 0, 244, 109, 236, 0, 16, 0, 119, 0, 213, 250, 0, 0, 0, + 0, 0, 128, 162, 30, 26, 18, 1, 0, 2, 0, 16, 0, 34, 1, 66, 4, 0, 0, 93, 0, 91, 120, 112, + 99, 115, 101, 114, 118, 105, 99, 101, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, + 67, 114, 121, 112, 116, 111, 84, 111, 107, 101, 110, 75, 105, 116, 46, 112, 105, 118, + 116, 111, 107, 101, 110, 40, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, + 112, 112, 108, 101, 46, 99, 116, 107, 100, 40, 53, 48, 49, 41, 62, 58, 52, 53, 50, 93, + 41, 40, 53, 48, 49, 41, 62, 58, 52, 50, 51, 49, 93, 0, 0, 4, 0, 45, 2, 240, 253, 31, + 18, 53, 234, 0, 0, 0, 0, 0, 0, 65, 165, 236, 0, 16, 0, 41, 0, 213, 250, 0, 0, 0, 0, 0, + 128, 54, 56, 26, 18, 1, 0, 2, 0, 16, 0, 34, 2, 66, 4, 0, 0, 5, 0, 2, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 52, 50, 51, 49, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 160, 254, 31, 18, 53, + 234, 0, 0, 0, 0, 0, 0, 140, 217, 236, 0, 16, 0, 31, 0, 213, 250, 0, 0, 0, 0, 0, 128, + 227, 61, 26, 18, 1, 0, 2, 0, 16, 0, 34, 1, 66, 4, 0, 0, 5, 0, 52, 50, 51, 49, 0, 0, 2, + 1, 61, 2, 192, 250, 31, 18, 53, 234, 0, 0, 0, 0, 0, 0, 64, 66, 14, 1, 16, 0, 40, 0, + 193, 250, 0, 0, 0, 0, 0, 128, 196, 1, 0, 0, 0, 0, 0, 0, 193, 250, 0, 0, 0, 0, 0, 128, + 214, 250, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, + 18, 53, 234, 0, 0, 0, 0, 0, 0, 237, 112, 14, 1, 16, 0, 181, 0, 214, 250, 0, 0, 0, 0, 0, + 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 115, 0, 66, 4, 115, 0, 34, + 0, 50, 51, 54, 45, 52, 53, 50, 45, 49, 50, 57, 50, 32, 40, 116, 97, 114, 103, 101, 116, + 58, 91, 120, 112, 99, 115, 101, 114, 118, 105, 99, 101, 60, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 67, 114, 121, 112, 116, 111, 84, 111, 107, 101, 110, 75, 105, 116, + 46, 112, 105, 118, 116, 111, 107, 101, 110, 40, 91, 100, 97, 101, 109, 111, 110, 60, + 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 116, 107, 100, 40, 53, 48, 49, 41, + 62, 58, 52, 53, 50, 93, 41, 40, 53, 48, 49, 41, 62, 58, 52, 50, 51, 49, 93, 41, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 116, + 107, 100, 40, 53, 48, 49, 41, 62, 58, 52, 53, 50, 93, 0, 0, 0, 0, 2, 1, 61, 2, 160, + 250, 31, 18, 53, 234, 0, 0, 0, 0, 0, 0, 126, 67, 16, 1, 16, 0, 40, 0, 193, 250, 0, 0, + 0, 0, 0, 128, 196, 1, 0, 0, 0, 0, 0, 0, 193, 250, 0, 0, 0, 0, 0, 128, 215, 250, 0, 0, + 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 53, 234, 0, 0, + 0, 0, 0, 0, 15, 88, 17, 1, 16, 0, 209, 1, 215, 250, 0, 0, 0, 0, 0, 128, 82, 115, 24, + 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 93, 0, 66, 4, 93, 0, 34, 0, 66, 4, 127, 0, + 44, 1, 91, 120, 112, 99, 115, 101, 114, 118, 105, 99, 101, 60, 99, 111, 109, 46, 97, + 112, 112, 108, 101, 46, 67, 114, 121, 112, 116, 111, 84, 111, 107, 101, 110, 75, 105, + 116, 46, 112, 105, 118, 116, 111, 107, 101, 110, 40, 91, 100, 97, 101, 109, 111, 110, + 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 116, 107, 100, 40, 53, 48, 49, + 41, 62, 58, 52, 53, 50, 93, 41, 40, 53, 48, 49, 41, 62, 58, 52, 50, 51, 49, 93, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 116, + 107, 100, 40, 53, 48, 49, 41, 62, 58, 52, 53, 50, 93, 0, 60, 82, 66, 83, 65, 115, 115, + 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, + 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 101, 120, 116, 101, 110, 115, 105, + 111, 110, 46, 115, 101, 115, 115, 105, 111, 110, 34, 32, 73, 68, 58, 50, 51, 54, 45, + 52, 53, 50, 45, 49, 50, 57, 51, 32, 116, 97, 114, 103, 101, 116, 58, 52, 50, 51, 49, + 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 76, + 101, 103, 97, 99, 121, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 114, 101, + 113, 117, 101, 115, 116, 101, 100, 82, 101, 97, 115, 111, 110, 58, 86, 105, 101, 119, + 83, 101, 114, 118, 105, 99, 101, 32, 114, 101, 97, 115, 111, 110, 58, 86, 105, 101, + 119, 83, 101, 114, 118, 105, 99, 101, 32, 102, 108, 97, 103, 115, 58, 40, 32, 65, 108, + 108, 111, 119, 73, 100, 108, 101, 83, 108, 101, 101, 112, 32, 80, 114, 101, 118, 101, + 110, 116, 84, 97, 115, 107, 83, 117, 115, 112, 101, 110, 100, 32, 80, 114, 101, 118, + 101, 110, 116, 84, 97, 115, 107, 84, 104, 114, 111, 116, 116, 108, 101, 68, 111, 119, + 110, 32, 41, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, + 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, + 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 86, + 97, 108, 105, 100, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 45, 2, 48, 187, 31, 18, 53, 234, 0, 0, 0, 0, 0, 0, 146, 111, 17, 1, 16, 0, 39, 0, + 215, 250, 0, 0, 0, 0, 0, 128, 61, 86, 23, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, + 13, 0, 50, 51, 54, 45, 52, 53, 50, 45, 49, 50, 57, 51, 0, 0, 4, 0, 45, 2, 112, 204, 31, + 18, 53, 234, 0, 0, 0, 0, 0, 0, 247, 170, 17, 1, 16, 0, 141, 0, 215, 250, 0, 0, 0, 0, 0, + 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 115, 0, 50, 51, 54, 45, + 52, 53, 50, 45, 49, 50, 57, 51, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 120, 112, + 99, 115, 101, 114, 118, 105, 99, 101, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, + 67, 114, 121, 112, 116, 111, 84, 111, 107, 101, 110, 75, 105, 116, 46, 112, 105, 118, + 116, 111, 107, 101, 110, 40, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, + 112, 112, 108, 101, 46, 99, 116, 107, 100, 40, 53, 48, 49, 41, 62, 58, 52, 53, 50, 93, + 41, 40, 53, 48, 49, 41, 62, 58, 52, 50, 51, 49, 93, 41, 0, 0, 0, 0, 2, 1, 61, 2, 180, + 201, 31, 18, 54, 234, 0, 0, 0, 0, 0, 0, 246, 130, 18, 1, 16, 0, 40, 0, 215, 250, 0, 0, + 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 215, 250, 0, 0, 0, 0, 0, 128, 216, 250, 0, 0, + 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 2, 1, 61, 2, 180, 201, 31, 18, 235, 233, 0, + 0, 0, 0, 0, 0, 167, 225, 152, 7, 16, 0, 40, 0, 214, 250, 0, 0, 0, 0, 0, 128, 236, 0, 0, + 0, 0, 0, 0, 0, 214, 250, 0, 0, 0, 0, 0, 128, 217, 250, 0, 0, 0, 0, 0, 128, 64, 63, 24, + 18, 1, 0, 2, 0, 2, 1, 61, 2, 96, 200, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 72, 178, 155, + 7, 16, 0, 40, 0, 214, 250, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 214, 250, 0, + 0, 0, 0, 0, 128, 218, 250, 0, 0, 0, 0, 0, 128, 7, 35, 24, 18, 1, 0, 2, 0, 2, 1, 44, 0, + 160, 250, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 129, 38, 41, 167, 17, 0, 16, 0, 219, 250, + 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 235, + 233, 0, 0, 0, 0, 0, 0, 185, 178, 43, 167, 17, 0, 113, 1, 219, 250, 0, 0, 0, 0, 0, 128, + 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 39, 0, 66, 4, 39, 0, 30, 0, 66, + 4, 69, 0, 6, 1, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, + 51, 53, 52, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 112, 111, 119, 101, 114, 100, 62, 58, 57, 55, 93, 0, 60, 82, 66, 83, 65, + 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, + 124, 32, 34, 65, 112, 112, 32, 105, 115, 32, 104, 111, 108, 100, 105, 110, 103, 32, + 112, 111, 119, 101, 114, 32, 97, 115, 115, 101, 114, 116, 105, 111, 110, 34, 32, 73, + 68, 58, 50, 51, 54, 45, 57, 55, 45, 49, 50, 57, 52, 32, 116, 97, 114, 103, 101, 116, + 58, 51, 53, 52, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, + 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, + 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, + 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 80, 111, 119, 101, 114, + 65, 115, 115, 101, 114, 116, 105, 111, 110, 34, 32, 115, 111, 117, 114, 99, 101, 69, + 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, + 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, + 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, + 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, + 45, 2, 112, 204, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 93, 46, 45, 167, 17, 0, 86, 0, + 219, 250, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, + 60, 0, 50, 51, 54, 45, 57, 55, 45, 49, 50, 57, 52, 32, 40, 116, 97, 114, 103, 101, 116, + 58, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, + 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, 51, 53, 52, + 93, 41, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 164, 134, + 47, 167, 17, 0, 40, 0, 219, 250, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 219, + 250, 0, 0, 0, 0, 0, 128, 220, 250, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, + 0, 45, 2, 64, 239, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 147, 194, 50, 167, 17, 0, 65, 0, + 219, 250, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, + 39, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, 51, 53, + 52, 93, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 78, 235, 0, 0, 0, 0, 0, + 0, 26, 197, 50, 167, 17, 0, 65, 0, 219, 250, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, + 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 39, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, + 108, 112, 101, 114, 62, 58, 51, 53, 52, 93, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 64, + 237, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 168, 199, 50, 167, 17, 0, 65, 0, 219, 250, 0, + 0, 0, 0, 0, 128, 106, 208, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 39, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 98, 97, + 99, 107, 117, 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, 51, 53, 52, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 73, 202, + 50, 167, 17, 0, 65, 0, 219, 250, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, + 0, 34, 1, 66, 4, 0, 0, 39, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, + 97, 112, 112, 108, 101, 46, 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, 108, 112, + 101, 114, 62, 58, 51, 53, 52, 93, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 64, 240, 31, 18, + 78, 235, 0, 0, 0, 0, 0, 0, 114, 210, 50, 167, 17, 0, 65, 0, 219, 250, 0, 0, 0, 0, 0, + 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 39, 0, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 98, 97, 99, 107, 117, + 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, 51, 53, 52, 93, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 1, 44, 0, 192, 250, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 68, 113, 57, 167, 17, + 0, 16, 0, 221, 250, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, + 206, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 157, 247, 57, 167, 17, 0, 122, 0, 221, 250, 0, + 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 60, 0, 66, 4, + 60, 0, 30, 0, 50, 51, 54, 45, 57, 55, 45, 49, 50, 57, 52, 32, 40, 116, 97, 114, 103, + 101, 116, 58, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, 51, + 53, 52, 93, 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 112, 111, 119, 101, 114, 100, 62, 58, 57, 55, 93, 0, 0, 0, 0, 0, 0, 0, 2, + 1, 44, 0, 192, 250, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 36, 135, 24, 172, 17, 0, 16, 0, + 222, 250, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, + 18, 80, 235, 0, 0, 0, 0, 0, 0, 96, 202, 24, 172, 17, 0, 135, 0, 222, 250, 0, 0, 0, 0, + 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 62, 0, 66, 4, 62, 0, + 41, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 50, 56, 50, 32, 40, 116, 97, 114, 103, 101, + 116, 58, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 108, 111, 103, 105, 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, 49, + 54, 52, 93, 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, + 62, 58, 49, 53, 55, 93, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, + 135, 187, 74, 172, 17, 0, 16, 0, 223, 250, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, + 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 22, 255, 76, 172, 17, 0, + 105, 1, 223, 250, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, + 0, 0, 68, 0, 66, 4, 68, 0, 53, 0, 66, 4, 121, 0, 202, 0, 91, 97, 112, 112, 60, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, + 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, + 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, + 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 99, 111, 114, 101, 115, 101, 114, 118, 105, 99, 101, 115, 46, 108, 97, 117, 110, + 99, 104, 115, 101, 114, 118, 105, 99, 101, 115, 100, 62, 58, 49, 50, 55, 93, 0, 60, 82, + 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, + 116, 111, 114, 124, 32, 34, 102, 114, 111, 110, 116, 109, 111, 115, 116, 58, 52, 52, + 52, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 50, 55, 45, 49, 50, 57, 53, 32, 116, 97, + 114, 103, 101, 116, 58, 52, 52, 52, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, + 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, + 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 108, 97, 117, 110, 99, 104, 115, 101, 114, 118, 105, 99, 101, 115, + 100, 34, 32, 110, 97, 109, 101, 58, 34, 82, 111, 108, 101, 85, 115, 101, 114, 73, 110, + 116, 101, 114, 97, 99, 116, 105, 118, 101, 70, 111, 99, 97, 108, 34, 32, 115, 111, 117, + 114, 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, + 117, 108, 108, 41, 34, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 112, + 204, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 109, 109, 78, 172, 17, 0, 116, 0, 223, 250, 0, + 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 90, 0, 50, + 51, 54, 45, 49, 50, 55, 45, 49, 50, 57, 53, 32, 40, 116, 97, 114, 103, 101, 116, 58, + 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, + 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, + 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, + 48, 49, 41, 62, 58, 52, 52, 52, 93, 41, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 168, + 15, 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 192, 1, 0, 0, 0, 0, 0, 0, 152, 15, 0, + 16, 0, 0, 0, 3, 245, 50, 18, 216, 116, 4, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 235, + 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 40, 0, 223, 250, 0, 0, 0, 0, 0, 128, 236, 0, + 0, 0, 0, 0, 0, 0, 223, 250, 0, 0, 0, 0, 0, 128, 128, 251, 0, 0, 0, 0, 0, 128, 64, 63, + 24, 18, 1, 0, 2, 0, 2, 1, 61, 2, 160, 250, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 121, 132, + 0, 0, 16, 0, 40, 0, 65, 251, 0, 0, 0, 0, 0, 128, 164, 0, 0, 0, 0, 0, 0, 0, 65, 251, 0, + 0, 0, 0, 0, 128, 129, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, + 2, 64, 239, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 188, 178, 3, 0, 16, 0, 94, 0, 223, 250, + 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, + 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, + 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, + 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 79, 235, 0, + 0, 0, 0, 0, 0, 123, 181, 3, 0, 16, 0, 94, 0, 223, 250, 0, 0, 0, 0, 0, 128, 115, 205, + 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, + 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, + 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, + 93, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 59, 185, 3, 0, + 16, 0, 94, 0, 223, 250, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, + 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, + 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, + 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 16, + 206, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 96, 250, 3, 0, 16, 0, 114, 1, 129, 251, 0, 0, + 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 40, 0, 66, 4, 40, + 0, 30, 0, 66, 4, 70, 0, 6, 1, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, + 97, 112, 112, 108, 101, 46, 108, 111, 103, 105, 110, 119, 105, 110, 100, 111, 119, 62, + 58, 49, 54, 52, 58, 49, 54, 52, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, + 109, 46, 97, 112, 112, 108, 101, 46, 112, 111, 119, 101, 114, 100, 62, 58, 57, 55, 93, + 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, + 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 32, 105, 115, 32, 104, 111, 108, + 100, 105, 110, 103, 32, 112, 111, 119, 101, 114, 32, 97, 115, 115, 101, 114, 116, 105, + 111, 110, 34, 32, 73, 68, 58, 50, 51, 54, 45, 57, 55, 45, 49, 50, 57, 54, 32, 116, 97, + 114, 103, 101, 116, 58, 49, 54, 52, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, + 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, + 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 80, + 111, 119, 101, 114, 65, 115, 115, 101, 114, 116, 105, 111, 110, 34, 32, 115, 111, 117, + 114, 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, + 117, 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, + 116, 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, + 105, 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, + 114, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 81, 235, 0, 0, 0, 0, 0, 0, 48, 132, 4, 0, 16, 0, + 136, 0, 223, 250, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, + 0, 0, 62, 0, 66, 4, 62, 0, 15, 0, 66, 4, 77, 0, 21, 0, 97, 112, 112, 60, 97, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, + 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, + 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, + 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, + 101, 114, 97, 99, 116, 105, 118, 101, 70, 111, 99, 97, 108, 0, 4, 0, 45, 2, 112, 204, + 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 232, 32, 5, 0, 16, 0, 87, 0, 129, 251, 0, 0, 0, 0, + 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 61, 0, 50, 51, 54, 45, + 57, 55, 45, 49, 50, 57, 54, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 108, 111, 103, 105, + 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, 49, 54, 52, 93, 41, 0, 0, 2, + 1, 44, 0, 192, 250, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 209, 208, 6, 0, 16, 0, 16, 0, + 130, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 2, 1, 61, 2, 180, 201, 31, + 18, 235, 233, 0, 0, 0, 0, 0, 0, 80, 209, 6, 0, 16, 0, 40, 0, 129, 251, 0, 0, 0, 0, 0, + 128, 236, 0, 0, 0, 0, 0, 0, 0, 129, 251, 0, 0, 0, 0, 0, 128, 131, 251, 0, 0, 0, 0, 0, + 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 80, 235, 0, 0, 0, 0, 0, + 0, 210, 121, 9, 0, 16, 0, 147, 0, 130, 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, + 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 62, 0, 66, 4, 62, 0, 53, 0, 50, 51, 54, 45, 49, 50, + 55, 45, 49, 50, 55, 53, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 100, 97, 101, 109, + 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 108, 111, 103, 105, 110, + 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, 49, 54, 52, 93, 41, 0, 91, 100, + 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 114, + 101, 115, 101, 114, 118, 105, 99, 101, 115, 46, 108, 97, 117, 110, 99, 104, 115, 101, + 114, 118, 105, 99, 101, 115, 100, 62, 58, 49, 50, 55, 93, 0, 0, 0, 0, 0, 0, 4, 0, 45, + 2, 64, 239, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 154, 166, 9, 0, 16, 0, 66, 0, 129, 251, + 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 40, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 108, + 111, 103, 105, 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, 49, 54, 52, + 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 50, + 169, 9, 0, 16, 0, 66, 0, 129, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, + 14, 0, 34, 1, 66, 4, 0, 0, 40, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, + 46, 97, 112, 112, 108, 101, 46, 108, 111, 103, 105, 110, 119, 105, 110, 100, 111, 119, + 62, 58, 49, 54, 52, 58, 49, 54, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, + 18, 78, 235, 0, 0, 0, 0, 0, 0, 167, 172, 9, 0, 16, 0, 66, 0, 129, 251, 0, 0, 0, 0, 0, + 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 40, 0, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 108, 111, 103, 105, + 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, 49, 54, 52, 93, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 45, 2, 64, 240, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 51, 180, 9, 0, 16, 0, + 66, 0, 129, 251, 0, 0, 0, 0, 0, 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, + 0, 0, 40, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 108, 111, 103, 105, 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, + 49, 54, 52, 93, 0, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 80, 235, 0, 0, 0, + 0, 0, 0, 35, 77, 10, 0, 16, 0, 16, 0, 132, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, + 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 164, 233, 11, 0, 16, + 0, 98, 1, 132, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, + 4, 0, 0, 68, 0, 66, 4, 68, 0, 53, 0, 66, 4, 121, 0, 195, 0, 91, 97, 112, 112, 60, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, + 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, + 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, + 52, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 99, 111, 114, 101, 115, 101, 114, 118, 105, 99, 101, 115, 46, 108, 97, 117, + 110, 99, 104, 115, 101, 114, 118, 105, 99, 101, 115, 100, 62, 58, 49, 50, 55, 93, 0, + 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 110, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, + 110, 58, 52, 52, 52, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 50, 55, 45, 49, 50, 57, + 55, 32, 116, 97, 114, 103, 101, 116, 58, 52, 52, 52, 32, 97, 116, 116, 114, 105, 98, + 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, + 116, 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 108, 97, 117, 110, 99, 104, 115, 101, 114, + 118, 105, 99, 101, 115, 100, 34, 32, 110, 97, 109, 101, 58, 34, 76, 83, 78, 111, 116, + 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 115, 111, 117, 114, 99, 101, 69, + 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, + 34, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 80, 235, 0, + 0, 0, 0, 0, 0, 246, 203, 12, 0, 16, 0, 116, 0, 132, 251, 0, 0, 0, 0, 0, 128, 210, 109, + 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 90, 0, 50, 51, 54, 45, 49, 50, 55, 45, + 49, 50, 57, 55, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, + 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, + 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, + 93, 41, 0, 0, 0, 0, 0, 2, 1, 61, 2, 192, 250, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 62, + 90, 14, 0, 16, 0, 40, 0, 65, 251, 0, 0, 0, 0, 0, 128, 164, 0, 0, 0, 0, 0, 0, 0, 65, + 251, 0, 0, 0, 0, 0, 128, 134, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 2, + 1, 61, 2, 180, 201, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 95, 62, 14, 0, 16, 0, 40, 0, + 132, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 132, 251, 0, 0, 0, 0, 0, 128, + 133, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, + 18, 80, 235, 0, 0, 0, 0, 0, 0, 54, 40, 17, 0, 16, 0, 123, 0, 134, 251, 0, 0, 0, 0, 0, + 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 61, 0, 66, 4, 61, 0, 30, + 0, 50, 51, 54, 45, 57, 55, 45, 49, 50, 57, 54, 32, 40, 116, 97, 114, 103, 101, 116, 58, + 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 108, + 111, 103, 105, 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, 49, 54, 52, + 93, 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 112, 111, 119, 101, 114, 100, 62, 58, 57, 55, 93, 0, 0, 0, 0, 0, 0, 4, 0, 45, + 2, 64, 239, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 79, 167, 17, 0, 16, 0, 94, 0, 132, 251, + 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, + 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, + 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, + 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 80, 235, 0, + 0, 0, 0, 0, 0, 100, 169, 17, 0, 16, 0, 94, 0, 132, 251, 0, 0, 0, 0, 0, 128, 115, 205, + 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, + 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, + 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, + 93, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 211, 172, 17, 0, + 16, 0, 94, 0, 132, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, + 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, + 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, + 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 48, + 14, 32, 18, 235, 233, 0, 0, 0, 0, 0, 0, 156, 123, 18, 0, 16, 0, 136, 0, 132, 251, 0, 0, + 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 62, 0, 66, 4, 62, + 0, 15, 0, 66, 4, 77, 0, 21, 0, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, + 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, + 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, + 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, 45, + 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, 116, + 105, 118, 101, 70, 111, 99, 97, 108, 0, 2, 1, 44, 0, 160, 250, 31, 18, 235, 233, 0, 0, + 0, 0, 0, 0, 169, 191, 49, 0, 16, 0, 16, 0, 135, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, + 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 26, 112, 51, + 0, 16, 0, 130, 1, 135, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, + 3, 66, 4, 0, 0, 68, 0, 66, 4, 68, 0, 41, 0, 66, 4, 109, 0, 239, 0, 91, 97, 112, 112, + 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, + 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, + 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, + 52, 52, 52, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, + 62, 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, + 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 86, 105, + 115, 105, 98, 108, 101, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 50, 57, + 56, 32, 116, 97, 114, 103, 101, 116, 58, 52, 52, 52, 32, 97, 116, 116, 114, 105, 98, + 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, + 116, 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, + 109, 101, 58, 34, 65, 112, 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, 115, 111, 117, + 114, 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, + 117, 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, + 116, 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, + 105, 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, + 114, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 180, 77, 52, 0, 16, + 0, 116, 0, 135, 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, + 66, 4, 0, 0, 90, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 50, 57, 56, 32, 40, 116, 97, + 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, + 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, + 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 41, 0, 0, 0, 0, 0, 2, 1, + 61, 2, 180, 201, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 182, 176, 53, 0, 16, 0, 40, 0, 135, + 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 135, 251, 0, 0, 0, 0, 0, 128, 136, + 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 235, + 233, 0, 0, 0, 0, 0, 0, 12, 7, 57, 0, 16, 0, 94, 0, 135, 251, 0, 0, 0, 0, 0, 128, 198, + 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, + 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, + 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, + 52, 93, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 240, 15, 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, + 0, 0, 0, 192, 1, 0, 0, 0, 0, 0, 0, 224, 15, 0, 16, 0, 0, 0, 3, 192, 60, 75, 216, 116, + 4, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, + 94, 0, 135, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, + 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, + 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, + 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, + 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, + 235, 233, 0, 0, 0, 0, 0, 0, 48, 53, 0, 0, 16, 0, 94, 0, 135, 251, 0, 0, 0, 0, 0, 128, + 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, + 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, + 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, + 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, + 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 80, 235, 0, 0, 0, 0, 0, 0, 145, + 96, 0, 0, 16, 0, 136, 0, 135, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, + 0, 34, 3, 66, 4, 0, 0, 62, 0, 66, 4, 62, 0, 15, 0, 66, 4, 77, 0, 21, 0, 97, 112, 112, + 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, + 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, + 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 0, + 114, 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, + 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 70, 111, 99, 97, 108, 0, 2, 1, + 44, 0, 160, 250, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 105, 186, 4, 0, 16, 0, 16, 0, 137, + 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 80, + 235, 0, 0, 0, 0, 0, 0, 109, 190, 6, 0, 16, 0, 134, 1, 137, 251, 0, 0, 0, 0, 0, 128, 82, + 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 72, 0, 66, 4, 72, 0, 41, 0, 66, 4, + 113, 0, 239, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, + 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, + 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, + 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, 52, 93, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, + 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, + 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, + 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 50, 57, 57, 32, 116, 97, 114, 103, 101, + 116, 58, 52, 48, 52, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, + 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, + 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 65, 112, 112, 86, + 105, 115, 105, 98, 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, + 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, + 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, + 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, + 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 80, + 235, 0, 0, 0, 0, 0, 0, 208, 175, 7, 0, 16, 0, 120, 0, 137, 251, 0, 0, 0, 0, 0, 128, + 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 94, 0, 50, 51, 54, 45, 49, 53, + 55, 45, 49, 50, 57, 57, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, + 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, + 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, + 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, + 48, 49, 41, 62, 58, 52, 48, 52, 93, 41, 0, 2, 1, 61, 2, 180, 201, 31, 18, 78, 235, 0, + 0, 0, 0, 0, 0, 97, 27, 9, 0, 16, 0, 40, 0, 137, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, + 0, 0, 0, 0, 137, 251, 0, 0, 0, 0, 0, 128, 138, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, + 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 179, 255, 12, 0, + 16, 0, 98, 0, 137, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, + 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, + 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, + 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, 52, 93, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 179, 2, 13, 0, 16, + 0, 98, 0, 137, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, + 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, + 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, + 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, + 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, 52, 93, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 61, 6, 13, 0, 16, 0, + 98, 0, 137, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, + 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, + 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, + 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, + 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, 52, 93, 0, 0, 0, 0, 0, 0, + 0, 4, 0, 45, 2, 48, 14, 32, 18, 235, 233, 0, 0, 0, 0, 0, 0, 104, 127, 13, 0, 16, 0, + 143, 0, 137, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, + 0, 0, 66, 0, 66, 4, 66, 0, 15, 0, 66, 4, 81, 0, 24, 0, 97, 112, 112, 60, 97, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, + 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, + 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, + 0, 114, 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, + 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 78, 111, 110, 70, 111, 99, 97, + 108, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 190, 179, 18, 0, + 16, 0, 16, 0, 139, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, + 16, 206, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 133, 81, 20, 0, 16, 0, 98, 1, 139, 251, 0, + 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 36, 0, 66, 4, + 36, 0, 41, 0, 66, 4, 77, 0, 239, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, + 46, 97, 112, 112, 108, 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, + 58, 52, 56, 53, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, + 56, 41, 62, 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, + 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, + 86, 105, 115, 105, 98, 108, 101, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, + 49, 51, 48, 48, 32, 116, 97, 114, 103, 101, 116, 58, 52, 56, 53, 32, 97, 116, 116, 114, + 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, + 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, + 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, 32, + 110, 97, 109, 101, 58, 34, 65, 112, 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, 115, + 111, 117, 114, 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, + 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, + 115, 105, 116, 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, + 116, 114, 105, 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, + 116, 101, 114, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, + 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 19, 20, + 21, 0, 16, 0, 84, 0, 139, 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, + 34, 1, 66, 4, 0, 0, 58, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 48, 32, 40, 116, + 97, 114, 103, 101, 116, 58, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, + 112, 112, 108, 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, + 56, 53, 93, 41, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 235, 233, 0, 0, 0, 0, 0, + 0, 193, 99, 22, 0, 16, 0, 40, 0, 139, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, + 0, 139, 251, 0, 0, 0, 0, 0, 128, 140, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, + 0, 4, 0, 45, 2, 64, 239, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 208, 52, 24, 0, 16, 0, 62, + 0, 139, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 36, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, + 0, 4, 0, 45, 2, 240, 236, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 4, 56, 24, 0, 16, 0, 62, + 0, 139, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 36, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, + 0, 4, 0, 45, 2, 144, 238, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 193, 59, 24, 0, 16, 0, 62, + 0, 139, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 36, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, + 0, 4, 0, 45, 2, 64, 240, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 27, 69, 24, 0, 16, 0, 62, + 0, 139, 251, 0, 0, 0, 0, 0, 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 36, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, + 0, 2, 1, 44, 0, 160, 250, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 41, 166, 92, 0, 16, 0, 16, + 0, 141, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, + 18, 81, 235, 0, 0, 0, 0, 0, 0, 205, 247, 94, 0, 16, 0, 213, 1, 141, 251, 0, 0, 0, 0, 0, + 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 36, 0, 66, 4, 36, 0, 36, + 0, 66, 4, 72, 0, 103, 1, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, + 112, 112, 108, 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, + 56, 53, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, + 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, + 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 78, 97, 112, 32, 97, 100, 97, 112, + 116, 101, 114, 32, 97, 115, 115, 101, 114, 116, 105, 111, 110, 34, 32, 73, 68, 58, 50, + 51, 54, 45, 52, 56, 53, 45, 49, 51, 48, 49, 32, 116, 97, 114, 103, 101, 116, 58, 52, + 56, 53, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, + 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, 112, 108, 101, + 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 112, 111, 108, + 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 62, 44, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, + 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, + 97, 112, 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, + 34, 69, 110, 97, 98, 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, + 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, + 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, + 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 80, 114, 101, + 118, 101, 110, 116, 84, 105, 109, 101, 114, 84, 104, 114, 111, 116, 116, 108, 101, 84, + 105, 101, 114, 52, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, 114, 111, + 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 10, 9, 93, 62, 0, + 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 222, 80, 96, 0, 16, + 0, 84, 0, 141, 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, + 4, 0, 0, 58, 0, 50, 51, 54, 45, 52, 56, 53, 45, 49, 51, 48, 49, 32, 40, 116, 97, 114, + 103, 101, 116, 58, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, + 41, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 242, 189, + 97, 0, 16, 0, 40, 0, 141, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 141, 251, + 0, 0, 0, 0, 0, 128, 142, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, + 2, 64, 239, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 72, 212, 100, 0, 16, 0, 62, 0, 141, 251, + 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 36, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, 105, + 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, 0, 4, 0, 45, 2, + 240, 236, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 220, 214, 100, 0, 16, 0, 62, 0, 141, 251, + 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 36, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, 105, + 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, 0, 4, 0, 45, 2, + 144, 238, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 234, 218, 100, 0, 16, 0, 62, 0, 141, 251, + 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 36, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, 105, + 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, 0, 4, 0, 45, 2, + 64, 240, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 203, 229, 100, 0, 16, 0, 62, 0, 141, 251, + 0, 0, 0, 0, 0, 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 36, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, 105, + 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, 0, 2, 1, 44, 0, + 192, 250, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 194, 66, 104, 0, 16, 0, 16, 0, 143, 251, + 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 235, + 233, 0, 0, 0, 0, 0, 0, 112, 114, 104, 0, 16, 0, 126, 0, 143, 251, 0, 0, 0, 0, 0, 128, + 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 58, 0, 66, 4, 58, 0, 36, 0, 50, + 51, 54, 45, 52, 56, 53, 45, 49, 50, 56, 51, 32, 40, 116, 97, 114, 103, 101, 116, 58, + 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, + 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 41, 0, 91, 100, + 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, 105, 110, + 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, 0, 2, 1, 61, 2, 180, + 201, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 219, 33, 172, 0, 16, 0, 40, 0, 221, 250, 0, 0, + 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 221, 250, 0, 0, 0, 0, 0, 128, 144, 251, 0, 0, + 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 2, 1, 61, 2, 96, 200, 31, 18, 78, 235, 0, 0, + 0, 0, 0, 0, 245, 130, 177, 0, 16, 0, 40, 0, 221, 250, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, + 0, 0, 0, 0, 221, 250, 0, 0, 0, 0, 0, 128, 145, 251, 0, 0, 0, 0, 0, 128, 7, 35, 24, 18, + 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 157, 128, 181, 0, + 16, 0, 66, 0, 145, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, + 66, 4, 0, 0, 40, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 108, 111, 103, 105, 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, + 54, 52, 58, 49, 54, 52, 93, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 8, 15, 0, 0, + 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 192, 1, 0, 0, 0, 0, 0, 0, 248, 14, 0, 16, 0, 0, + 0, 3, 183, 208, 0, 217, 116, 4, 0, 0, 4, 0, 45, 2, 64, 239, 31, 18, 78, 235, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 16, 0, 65, 0, 145, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, + 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 39, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, + 108, 112, 101, 114, 62, 58, 51, 53, 52, 93, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, + 236, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 239, 20, 0, 0, 16, 0, 65, 0, 145, 251, 0, 0, 0, + 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 39, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 98, 97, 99, 107, + 117, 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, 51, 53, 52, 93, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 45, 2, 64, 237, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 36, 24, 0, 0, 16, 0, + 65, 0, 145, 251, 0, 0, 0, 0, 0, 128, 106, 208, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, + 0, 0, 39, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, 51, + 53, 52, 93, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 78, 235, 0, 0, 0, 0, + 0, 0, 129, 26, 0, 0, 16, 0, 65, 0, 145, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, + 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 39, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, + 109, 46, 97, 112, 112, 108, 101, 46, 98, 97, 99, 107, 117, 112, 100, 45, 104, 101, 108, + 112, 101, 114, 62, 58, 51, 53, 52, 93, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 64, 239, + 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 169, 33, 0, 0, 16, 0, 62, 0, 145, 251, 0, 0, 0, 0, + 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 36, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, 105, 110, + 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, 0, 4, 0, 45, 2, 240, + 236, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 18, 36, 0, 0, 16, 0, 62, 0, 145, 251, 0, 0, 0, + 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 36, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, 105, 110, + 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, 0, 4, 0, 45, 2, 144, + 238, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 105, 39, 0, 0, 16, 0, 62, 0, 145, 251, 0, 0, 0, + 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 36, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 70, 105, 110, + 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, 0, 4, 0, 45, 2, 64, + 240, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 186, 39, 0, 0, 16, 0, 65, 0, 145, 251, 0, 0, 0, + 0, 0, 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 39, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 98, 97, 99, 107, + 117, 112, 100, 45, 104, 101, 108, 112, 101, 114, 62, 58, 51, 53, 52, 93, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 45, 2, 64, 240, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 161, 47, 0, 0, 16, 0, + 62, 0, 145, 251, 0, 0, 0, 0, 0, 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, + 0, 0, 36, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 70, 105, 110, 100, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 53, 93, 0, 0, + 0, 4, 0, 45, 2, 240, 236, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 99, 161, 0, 0, 16, 0, 66, + 0, 145, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 40, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 108, 111, 103, 105, 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, + 49, 54, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 235, 233, 0, 0, 0, + 0, 0, 0, 201, 164, 0, 0, 16, 0, 66, 0, 145, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, + 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 40, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 108, 111, 103, 105, 110, 119, 105, 110, 100, + 111, 119, 62, 58, 49, 54, 52, 58, 49, 54, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 64, + 240, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 3, 172, 0, 0, 16, 0, 66, 0, 145, 251, 0, 0, 0, + 0, 0, 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 40, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 108, 111, 103, + 105, 110, 119, 105, 110, 100, 111, 119, 62, 58, 49, 54, 52, 58, 49, 54, 52, 93, 0, 0, + 0, 0, 0, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 70, 208, 47, + 0, 16, 0, 16, 0, 146, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, + 2, 16, 206, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 56, 178, 49, 0, 16, 0, 130, 1, 146, 251, + 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 68, 0, 66, + 4, 68, 0, 41, 0, 66, 4, 109, 0, 239, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, + 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, + 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 91, 100, + 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, + 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, + 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 68, 114, 97, 119, 105, 110, 103, 34, 32, + 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 50, 32, 116, 97, 114, 103, 101, + 116, 58, 52, 52, 52, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, + 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, + 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 65, 112, 112, 68, + 114, 97, 119, 105, 110, 103, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, + 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, + 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, + 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, + 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 112, 204, + 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 218, 152, 50, 0, 16, 0, 116, 0, 146, 251, 0, 0, 0, + 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 90, 0, 50, 51, 54, + 45, 49, 53, 55, 45, 49, 51, 48, 50, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, + 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, + 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, + 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, + 41, 62, 58, 52, 52, 52, 93, 41, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 235, 233, + 0, 0, 0, 0, 0, 0, 20, 231, 51, 0, 16, 0, 40, 0, 146, 251, 0, 0, 0, 0, 0, 128, 236, 0, + 0, 0, 0, 0, 0, 0, 146, 251, 0, 0, 0, 0, 0, 128, 147, 251, 0, 0, 0, 0, 0, 128, 64, 63, + 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 204, 189, + 55, 0, 16, 0, 94, 0, 146, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, + 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, + 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, + 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, + 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, + 240, 236, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 249, 192, 55, 0, 16, 0, 94, 0, 146, 251, + 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, + 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, + 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, + 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 235, 233, + 0, 0, 0, 0, 0, 0, 49, 198, 55, 0, 16, 0, 94, 0, 146, 251, 0, 0, 0, 0, 0, 128, 74, 210, + 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, + 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, + 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, + 93, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 80, 235, 0, 0, 0, 0, 0, 0, 234, 248, 55, 0, + 16, 0, 136, 0, 146, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, + 66, 4, 0, 0, 62, 0, 66, 4, 62, 0, 15, 0, 66, 4, 77, 0, 21, 0, 97, 112, 112, 60, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, + 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, + 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 0, 114, + 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, + 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 70, 111, 99, 97, 108, 0, 2, 1, 44, 0, + 160, 250, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 127, 14, 224, 0, 16, 0, 16, 0, 148, 251, + 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 80, 235, + 0, 0, 0, 0, 0, 0, 54, 164, 225, 0, 16, 0, 155, 1, 148, 251, 0, 0, 0, 0, 0, 128, 82, + 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 72, 0, 66, 4, 72, 0, 41, 0, 66, 4, + 113, 0, 4, 1, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, + 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, + 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, + 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, 52, 93, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, + 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, + 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 70, 85, 83, 66, 80, 114, 111, 99, 101, 115, 115, 87, + 105, 110, 100, 111, 119, 83, 116, 97, 116, 101, 58, 32, 118, 105, 115, 105, 98, 108, + 101, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 51, 32, 116, 97, + 114, 103, 101, 116, 58, 52, 48, 52, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, + 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, + 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 102, 117, 115, 101, 98, 111, 97, 114, 100, 34, 32, 110, 97, 109, + 101, 58, 34, 86, 105, 115, 105, 98, 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, + 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, + 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, + 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, + 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, + 112, 204, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 138, 153, 226, 0, 16, 0, 120, 0, 148, 251, + 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 94, 0, 50, + 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 51, 32, 40, 116, 97, 114, 103, 101, 116, 58, + 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, + 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, + 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, + 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, 52, 93, 41, 0, 2, 1, 61, 2, 180, 201, 31, + 18, 79, 235, 0, 0, 0, 0, 0, 0, 118, 204, 227, 0, 16, 0, 40, 0, 148, 251, 0, 0, 0, 0, 0, + 128, 236, 0, 0, 0, 0, 0, 0, 0, 148, 251, 0, 0, 0, 0, 0, 128, 149, 251, 0, 0, 0, 0, 0, + 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 78, 235, 0, 0, 0, 0, 0, + 0, 134, 205, 229, 0, 16, 0, 98, 0, 148, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, + 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, + 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, + 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, + 48, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 78, 235, 0, 0, 0, 0, 0, + 0, 129, 207, 229, 0, 16, 0, 98, 0, 148, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, + 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, + 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, + 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, + 48, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 78, 235, 0, 0, 0, 0, 0, + 0, 85, 210, 229, 0, 16, 0, 98, 0, 148, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, + 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, + 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, + 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, + 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 80, 235, 0, 0, 0, 0, 0, 0, + 146, 33, 230, 0, 16, 0, 143, 0, 148, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, + 0, 17, 0, 34, 3, 66, 4, 0, 0, 66, 0, 66, 4, 66, 0, 15, 0, 66, 4, 81, 0, 24, 0, 97, 112, + 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, + 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, + 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, + 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, + 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 78, 111, + 110, 70, 111, 99, 97, 108, 0, 0, 2, 1, 44, 0, 192, 250, 31, 18, 78, 235, 0, 0, 0, 0, 0, + 0, 198, 97, 232, 0, 16, 0, 16, 0, 150, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, + 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 98, 147, 232, 0, 16, 0, + 167, 0, 150, 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, + 0, 0, 94, 0, 66, 4, 94, 0, 41, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 50, 56, 53, 32, + 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, + 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, + 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, 52, + 93, 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, + 58, 49, 53, 55, 93, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, + 192, 38, 233, 0, 16, 0, 16, 0, 151, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, + 0, 1, 96, 0, 0, 0, 0, 0, 0, 40, 15, 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 192, 1, + 0, 0, 0, 0, 0, 0, 24, 15, 0, 16, 0, 0, 0, 3, 202, 43, 235, 217, 116, 4, 0, 0, 4, 0, 45, + 2, 16, 206, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 151, 1, 151, 251, 0, + 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 68, 0, 66, 4, + 68, 0, 41, 0, 66, 4, 109, 0, 4, 1, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, + 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, + 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, + 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, + 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 70, 85, 83, 66, 80, 114, 111, 99, 101, 115, 115, 87, + 105, 110, 100, 111, 119, 83, 116, 97, 116, 101, 58, 32, 118, 105, 115, 105, 98, 108, + 101, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 52, 32, 116, 97, + 114, 103, 101, 116, 58, 52, 52, 52, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, + 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, + 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 102, 117, 115, 101, 98, 111, 97, 114, 100, 34, 32, 110, 97, 109, + 101, 58, 34, 86, 105, 115, 105, 98, 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, + 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, + 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, + 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, + 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 4, 0, 45, 2, 112, 204, + 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 87, 249, 0, 0, 16, 0, 116, 0, 151, 251, 0, 0, 0, 0, + 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 90, 0, 50, 51, 54, 45, + 49, 53, 55, 45, 49, 51, 48, 52, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, + 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, + 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, + 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, + 58, 52, 52, 52, 93, 41, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 79, 235, 0, 0, 0, + 0, 0, 0, 251, 226, 1, 0, 16, 0, 40, 0, 151, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, + 0, 0, 0, 151, 251, 0, 0, 0, 0, 0, 128, 152, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, + 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 59, 64, 4, 0, 16, 0, + 94, 0, 151, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, + 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, + 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, + 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, + 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, + 80, 235, 0, 0, 0, 0, 0, 0, 27, 66, 4, 0, 16, 0, 94, 0, 151, 251, 0, 0, 0, 0, 0, 128, + 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, + 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, + 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, + 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, + 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 168, + 68, 4, 0, 16, 0, 94, 0, 151, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, + 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, + 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, + 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, + 2, 48, 14, 32, 18, 79, 235, 0, 0, 0, 0, 0, 0, 90, 147, 4, 0, 16, 0, 136, 0, 151, 251, + 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 62, 0, 66, + 4, 62, 0, 15, 0, 66, 4, 77, 0, 21, 0, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, + 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, + 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, + 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, + 116, 105, 118, 101, 70, 111, 99, 97, 108, 0, 2, 1, 44, 0, 192, 250, 31, 18, 80, 235, 0, + 0, 0, 0, 0, 0, 156, 174, 6, 0, 16, 0, 16, 0, 153, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, + 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 241, 218, 6, + 0, 16, 0, 163, 0, 153, 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, + 2, 66, 4, 0, 0, 90, 0, 66, 4, 90, 0, 41, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 50, 56, + 52, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, + 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, + 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 41, + 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, + 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, + 53, 55, 93, 0, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, + 63, 137, 97, 6, 16, 0, 40, 0, 150, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, + 150, 251, 0, 0, 0, 0, 0, 128, 154, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, + 2, 1, 61, 2, 96, 200, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 20, 67, 100, 6, 16, 0, 40, 0, + 150, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 150, 251, 0, 0, 0, 0, 0, 128, + 155, 251, 0, 0, 0, 0, 0, 128, 7, 35, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, + 81, 235, 0, 0, 0, 0, 0, 0, 222, 107, 101, 6, 16, 0, 94, 0, 155, 251, 0, 0, 0, 0, 0, + 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, + 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, + 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, + 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, + 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 39, + 110, 101, 6, 16, 0, 94, 0, 155, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, + 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 111, 114, 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, + 67, 104, 114, 111, 109, 105, 117, 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, + 51, 56, 49, 49, 53, 49, 40, 53, 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, + 2, 144, 238, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 171, 218, 101, 6, 16, 0, 94, 0, 155, + 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 68, 0, + 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, + 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, + 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, + 48, 49, 41, 62, 58, 52, 52, 52, 93, 0, 0, 0, 4, 0, 45, 2, 64, 239, 31, 18, 80, 235, 0, + 0, 0, 0, 0, 0, 76, 9, 102, 6, 16, 0, 98, 0, 155, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, + 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, + 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, + 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, + 58, 52, 48, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 80, 235, 0, 0, + 0, 0, 0, 0, 107, 11, 102, 6, 16, 0, 98, 0, 155, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, + 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, + 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, + 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, + 58, 52, 48, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 80, 235, 0, 0, + 0, 0, 0, 0, 34, 14, 102, 6, 16, 0, 98, 0, 155, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, + 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, + 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, + 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, + 58, 52, 48, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 78, 235, 0, 0, 0, + 0, 0, 0, 85, 215, 102, 6, 16, 0, 143, 0, 155, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, + 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 66, 0, 66, 4, 66, 0, 15, 0, 66, 4, 81, 0, 24, 0, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, + 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, + 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, + 56, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, + 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 78, + 111, 110, 70, 111, 99, 97, 108, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 78, 235, 0, 0, 0, 0, + 0, 0, 174, 28, 105, 6, 16, 0, 136, 0, 155, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, + 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 62, 0, 66, 4, 62, 0, 15, 0, 66, 4, 77, 0, 21, 0, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 111, 114, + 103, 46, 99, 104, 114, 111, 109, 105, 117, 109, 46, 67, 104, 114, 111, 109, 105, 117, + 109, 46, 51, 50, 51, 56, 49, 49, 52, 56, 46, 51, 50, 51, 56, 49, 49, 53, 49, 40, 53, + 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, 101, + 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 70, 111, 99, + 97, 108, 0, 2, 1, 44, 0, 160, 250, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 254, 203, 108, 6, + 16, 0, 16, 0, 156, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, + 16, 206, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 209, 39, 110, 6, 16, 0, 134, 1, 156, 251, + 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 72, 0, 66, + 4, 72, 0, 41, 0, 66, 4, 113, 0, 239, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, + 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, + 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, + 52, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, + 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, + 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 68, 114, 97, + 119, 105, 110, 103, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 53, + 32, 116, 97, 114, 103, 101, 116, 58, 52, 48, 52, 32, 97, 116, 116, 114, 105, 98, 117, + 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, + 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, + 109, 46, 97, 112, 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, + 101, 58, 34, 65, 112, 112, 68, 114, 97, 119, 105, 110, 103, 34, 32, 115, 111, 117, 114, + 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, + 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, + 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, + 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, + 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 4, 0, + 45, 2, 112, 204, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 100, 230, 110, 6, 16, 0, 120, 0, + 156, 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, + 94, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 53, 32, 40, 116, 97, 114, 103, 101, + 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, + 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, 99, + 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, + 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 58, 52, 48, 52, 93, 41, 0, 2, 1, 61, 2, + 180, 201, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 20, 218, 111, 6, 16, 0, 40, 0, 156, 251, + 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 156, 251, 0, 0, 0, 0, 0, 128, 157, 251, + 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 78, 235, + 0, 0, 0, 0, 0, 0, 70, 187, 113, 6, 16, 0, 98, 0, 156, 251, 0, 0, 0, 0, 0, 128, 198, + 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, + 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, + 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, + 41, 62, 58, 52, 48, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 78, + 235, 0, 0, 0, 0, 0, 0, 241, 188, 113, 6, 16, 0, 98, 0, 156, 251, 0, 0, 0, 0, 0, 128, + 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, + 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, + 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, + 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, + 48, 49, 41, 62, 58, 52, 48, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, + 78, 235, 0, 0, 0, 0, 0, 0, 84, 191, 113, 6, 16, 0, 98, 0, 156, 251, 0, 0, 0, 0, 0, 128, + 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 72, 0, 91, 97, 112, 112, 60, + 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 118, 105, + 115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 46, 99, 111, 100, 101, 46, 111, 115, + 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, + 48, 49, 41, 62, 58, 52, 48, 52, 93, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, + 78, 235, 0, 0, 0, 0, 0, 0, 129, 250, 113, 6, 16, 0, 143, 0, 156, 251, 0, 0, 0, 0, 0, + 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 66, 0, 66, 4, 66, 0, 15, + 0, 66, 4, 81, 0, 24, 0, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 99, 111, 109, 46, 118, 105, 115, 117, 97, 108, 115, 116, 117, 100, 105, + 111, 46, 99, 111, 100, 101, 46, 111, 115, 115, 46, 51, 50, 52, 52, 51, 53, 51, 51, 46, + 51, 50, 52, 52, 51, 53, 51, 56, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, + 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, + 97, 99, 116, 105, 118, 101, 78, 111, 110, 70, 111, 99, 97, 108, 0, 0, 2, 1, 44, 0, 160, + 250, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 124, 161, 133, 21, 16, 0, 16, 0, 158, 251, 0, + 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, + 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 192, 1, 0, 0, 0, 0, 0, 0, 240, 15, 0, 16, 0, 0, 0, + 3, 151, 96, 115, 239, 116, 4, 0, 0, 4, 0, 45, 2, 16, 206, 31, 18, 78, 235, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 16, 0, 105, 1, 158, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, + 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 43, 0, 66, 4, 43, 0, 41, 0, 66, 4, 84, 0, 239, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, + 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, + 56, 51, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, + 62, 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, + 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 68, 114, 97, + 119, 105, 110, 103, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 54, + 32, 116, 97, 114, 103, 101, 116, 58, 52, 56, 51, 32, 97, 116, 116, 114, 105, 98, 117, + 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, + 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, + 109, 46, 97, 112, 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, + 101, 58, 34, 65, 112, 112, 68, 114, 97, 119, 105, 110, 103, 34, 32, 115, 111, 117, 114, + 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, + 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, + 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, + 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, + 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 110, 167, 1, 0, 16, + 0, 91, 0, 158, 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, + 4, 0, 0, 65, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 54, 32, 40, 116, 97, 114, + 103, 101, 116, 58, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 99, 111, 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, + 48, 49, 41, 62, 58, 52, 56, 51, 93, 41, 0, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, + 18, 78, 235, 0, 0, 0, 0, 0, 0, 82, 106, 3, 0, 16, 0, 40, 0, 158, 251, 0, 0, 0, 0, 0, + 128, 236, 0, 0, 0, 0, 0, 0, 0, 158, 251, 0, 0, 0, 0, 0, 128, 159, 251, 0, 0, 0, 0, 0, + 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 81, 235, 0, 0, 0, 0, 0, + 0, 248, 168, 7, 0, 16, 0, 69, 0, 158, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, + 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, + 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, 114, 111, 108, 99, 101, 110, + 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, + 240, 236, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 214, 171, 7, 0, 16, 0, 69, 0, 158, 251, 0, + 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 43, 0, 91, + 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, + 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, + 56, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 67, + 176, 7, 0, 16, 0, 69, 0, 158, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, + 0, 34, 1, 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, + 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, + 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 64, 240, 31, + 18, 81, 235, 0, 0, 0, 0, 0, 0, 165, 190, 7, 0, 16, 0, 69, 0, 158, 251, 0, 0, 0, 0, 0, + 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, + 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, + 0, 0, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 210, 154, 14, 0, + 16, 0, 16, 0, 160, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, + 16, 206, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 247, 154, 16, 0, 16, 0, 135, 1, 160, 251, + 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 73, 0, 66, + 4, 73, 0, 41, 0, 66, 4, 114, 0, 239, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, + 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, + 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, + 49, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, + 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, + 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, + 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 68, 114, 97, + 119, 105, 110, 103, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 55, + 32, 116, 97, 114, 103, 101, 116, 58, 54, 52, 49, 32, 97, 116, 116, 114, 105, 98, 117, + 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, + 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, + 109, 46, 97, 112, 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, + 101, 58, 34, 65, 112, 112, 68, 114, 97, 119, 105, 110, 103, 34, 32, 115, 111, 117, 114, + 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, + 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, + 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, + 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, + 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 4, 0, 45, + 2, 112, 204, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 226, 159, 17, 0, 16, 0, 121, 0, 160, + 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 95, + 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 55, 32, 40, 116, 97, 114, 103, 101, 116, + 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, + 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, + 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, + 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 41, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 180, 255, 18, 0, 16, 0, + 40, 0, 160, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 160, 251, 0, 0, 0, 0, 0, + 128, 161, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, + 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 67, 37, 22, 0, 16, 0, 99, 0, 160, 251, 0, 0, 0, 0, + 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 73, 0, 91, 97, 112, + 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, + 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, + 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, + 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, + 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 14, 40, 22, 0, 16, 0, 99, 0, 160, 251, 0, 0, 0, 0, + 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 73, 0, 91, 97, 112, + 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, + 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, + 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, + 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, + 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 133, 43, 22, 0, 16, 0, 99, 0, 160, 251, 0, 0, 0, 0, + 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 73, 0, 91, 97, 112, + 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, + 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, + 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, + 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, + 18, 78, 235, 0, 0, 0, 0, 0, 0, 66, 146, 22, 0, 16, 0, 136, 0, 160, 251, 0, 0, 0, 0, 0, + 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 67, 0, 66, 4, 67, 0, 15, + 0, 66, 4, 82, 0, 16, 0, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, + 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, + 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, + 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, + 97, 99, 116, 105, 118, 101, 0, 2, 1, 44, 0, 160, 250, 31, 18, 78, 235, 0, 0, 0, 0, 0, + 0, 214, 10, 27, 0, 16, 0, 16, 0, 162, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, + 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 181, 169, 28, 0, 16, 0, + 145, 1, 162, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, + 0, 0, 83, 0, 66, 4, 83, 0, 41, 0, 66, 4, 124, 0, 239, 0, 91, 97, 112, 112, 60, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, + 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, + 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, + 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 0, 91, 100, + 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, + 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, + 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 68, 114, 97, 119, 105, 110, 103, 34, 32, + 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 56, 32, 116, 97, 114, 103, 101, + 116, 58, 54, 52, 51, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, + 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, + 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 65, 112, 112, 68, + 114, 97, 119, 105, 110, 103, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, + 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, + 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, + 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, + 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 112, + 204, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 127, 172, 29, 0, 16, 0, 131, 0, 162, 251, 0, 0, + 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 105, 0, 50, 51, + 54, 45, 49, 53, 55, 45, 49, 51, 48, 56, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, + 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, + 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, + 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, + 52, 51, 93, 41, 0, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 235, 233, 0, 0, 0, 0, + 0, 0, 46, 236, 30, 0, 16, 0, 40, 0, 162, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, + 0, 0, 162, 251, 0, 0, 0, 0, 0, 128, 163, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, + 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 91, 25, 34, 0, 16, 0, + 109, 0, 162, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, + 4, 0, 0, 83, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, + 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, + 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, + 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, + 48, 49, 41, 62, 58, 54, 52, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 235, + 233, 0, 0, 0, 0, 0, 0, 44, 28, 34, 0, 16, 0, 109, 0, 162, 251, 0, 0, 0, 0, 0, 128, 115, + 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 83, 0, 91, 97, 112, 112, 60, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, + 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, + 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, + 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 0, 0, + 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 200, 31, 34, 0, 16, 0, + 109, 0, 162, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, + 0, 0, 83, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, + 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, + 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, + 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, + 41, 62, 58, 54, 52, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 78, 235, 0, 0, 0, + 0, 0, 0, 216, 206, 34, 0, 16, 0, 146, 0, 162, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, + 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 77, 0, 66, 4, 77, 0, 15, 0, 66, 4, 92, 0, 16, 0, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, + 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, + 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, + 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 0, 114, + 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, + 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 0, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 160, + 250, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 87, 3, 39, 0, 16, 0, 16, 0, 164, 251, 0, 0, 0, + 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 235, 233, 0, 0, + 0, 0, 0, 0, 213, 221, 40, 0, 16, 0, 136, 1, 164, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, + 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 74, 0, 66, 4, 74, 0, 41, 0, 66, 4, 115, 0, + 239, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, + 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, + 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, + 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, + 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, + 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 68, 114, 97, 119, 105, 110, 103, 34, 32, + 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 48, 57, 32, 116, 97, 114, 103, 101, + 116, 58, 54, 52, 55, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, + 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, + 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 65, 112, 112, 68, + 114, 97, 119, 105, 110, 103, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, + 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, + 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, + 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, + 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 4, 0, 45, 2, 112, 204, 31, 18, 235, 233, + 0, 0, 0, 0, 0, 0, 192, 228, 41, 0, 16, 0, 122, 0, 164, 251, 0, 0, 0, 0, 0, 128, 210, + 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 96, 0, 50, 51, 54, 45, 49, 53, 55, + 45, 49, 51, 48, 57, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, + 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, + 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, + 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 41, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, + 0, 216, 15, 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 192, 1, 0, 0, 0, 0, 0, 0, 200, + 15, 0, 16, 0, 0, 0, 3, 44, 216, 158, 239, 116, 4, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, + 78, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 40, 0, 164, 251, 0, 0, 0, 0, 0, 128, 236, + 0, 0, 0, 0, 0, 0, 0, 164, 251, 0, 0, 0, 0, 0, 128, 165, 251, 0, 0, 0, 0, 0, 128, 64, + 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 169, + 12, 3, 0, 16, 0, 100, 0, 164, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, + 14, 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, + 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, + 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, + 55, 93, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 42, + 15, 3, 0, 16, 0, 100, 0, 164, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, + 14, 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, + 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, + 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, + 55, 93, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 134, + 18, 3, 0, 16, 0, 100, 0, 164, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, + 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, + 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, + 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, + 55, 93, 0, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 81, 235, 0, 0, 0, 0, 0, 0, 61, 105, + 3, 0, 16, 0, 137, 0, 164, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, + 34, 3, 66, 4, 0, 0, 68, 0, 66, 4, 68, 0, 15, 0, 66, 4, 83, 0, 16, 0, 97, 112, 112, 60, + 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, + 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, + 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, + 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, + 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 29, 103, + 6, 1, 16, 0, 16, 0, 166, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, + 45, 2, 16, 206, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 227, 87, 8, 1, 16, 0, 136, 1, 166, + 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 74, 0, + 66, 4, 74, 0, 41, 0, 66, 4, 115, 0, 239, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, + 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, + 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, + 62, 58, 54, 52, 55, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, + 112, 112, 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, + 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, + 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, + 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, + 45, 49, 51, 49, 48, 32, 116, 97, 114, 103, 101, 116, 58, 54, 52, 55, 32, 97, 116, 116, + 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, + 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, + 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, + 32, 110, 97, 109, 101, 58, 34, 65, 112, 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, + 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, + 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, + 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, + 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, + 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, + 62, 0, 4, 0, 45, 2, 112, 204, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 39, 76, 9, 1, 16, 0, + 122, 0, 166, 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, + 4, 0, 0, 96, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 48, 32, 40, 116, 97, 114, + 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, + 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, + 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, + 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 41, + 0, 0, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 45, 142, + 12, 1, 16, 0, 40, 0, 166, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 166, 251, + 0, 0, 0, 0, 0, 128, 167, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, + 2, 48, 14, 32, 18, 79, 235, 0, 0, 0, 0, 0, 0, 243, 189, 14, 1, 16, 0, 137, 0, 166, 251, + 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 68, 0, 66, + 4, 68, 0, 15, 0, 66, 4, 83, 0, 16, 0, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, + 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, + 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 0, 114, + 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, + 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, + 64, 239, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 117, 239, 14, 1, 16, 0, 100, 0, 166, 251, + 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, + 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, + 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, + 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 0, 0, 0, 0, 0, 4, 0, 45, 2, + 240, 236, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 144, 241, 14, 1, 16, 0, 100, 0, 166, 251, + 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, + 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, + 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, + 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 0, 0, 0, 0, 0, 4, 0, 45, 2, + 144, 238, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 204, 244, 14, 1, 16, 0, 100, 0, 166, 251, + 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, + 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, + 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, + 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 0, 0, 0, 0, 0, 2, 1, 44, 0, + 160, 250, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 121, 232, 18, 1, 16, 0, 16, 0, 168, 251, + 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 81, 235, + 0, 0, 0, 0, 0, 0, 181, 76, 20, 1, 16, 0, 145, 1, 168, 251, 0, 0, 0, 0, 0, 128, 82, 115, + 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 83, 0, 66, 4, 83, 0, 41, 0, 66, 4, 124, + 0, 239, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, + 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, + 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, + 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, + 41, 62, 58, 54, 52, 51, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, + 97, 112, 112, 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, + 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, + 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, 34, 65, 112, + 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, + 45, 49, 51, 49, 49, 32, 116, 97, 114, 103, 101, 116, 58, 54, 52, 51, 32, 97, 116, 116, + 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, + 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, + 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 97, 112, 112, 110, 97, 112, 34, + 32, 110, 97, 109, 101, 58, 34, 65, 112, 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, + 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, + 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, + 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, + 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, + 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, + 62, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, + 230, 1, 21, 1, 16, 0, 131, 0, 168, 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, + 0, 18, 0, 34, 1, 66, 4, 0, 0, 105, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 49, + 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, 120, + 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, 45, + 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, + 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 41, 0, 0, 0, 0, 0, 0, 2, 1, 61, + 2, 180, 201, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 45, 5, 22, 1, 16, 0, 40, 0, 168, 251, + 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 168, 251, 0, 0, 0, 0, 0, 128, 169, 251, + 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 78, 235, + 0, 0, 0, 0, 0, 0, 83, 43, 25, 1, 16, 0, 109, 0, 168, 251, 0, 0, 0, 0, 0, 128, 198, 202, + 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 83, 0, 91, 97, 112, 112, 60, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, + 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, + 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, + 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 0, 0, 0, 0, + 4, 0, 45, 2, 240, 236, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 220, 45, 25, 1, 16, 0, 109, + 0, 168, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 83, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, + 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, + 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, + 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, + 41, 62, 58, 54, 52, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 78, 235, 0, 0, + 0, 0, 0, 0, 7, 49, 25, 1, 16, 0, 109, 0, 168, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, + 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 83, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, + 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, + 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, + 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, + 48, 14, 32, 18, 78, 235, 0, 0, 0, 0, 0, 0, 115, 129, 25, 1, 16, 0, 146, 0, 168, 251, 0, + 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 77, 0, 66, 4, + 77, 0, 15, 0, 66, 4, 92, 0, 16, 0, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, + 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, + 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, + 55, 54, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, + 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, 118, + 101, 0, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, + 140, 208, 29, 1, 16, 0, 16, 0, 170, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, + 0, 4, 0, 45, 2, 16, 206, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 108, 72, 31, 1, 16, 0, 105, + 1, 170, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, + 0, 43, 0, 66, 4, 43, 0, 41, 0, 66, 4, 84, 0, 239, 0, 91, 100, 97, 101, 109, 111, 110, + 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, 114, 111, 108, 99, + 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, 0, 91, 100, 97, + 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, + 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, + 60, 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 65, 112, 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, + 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 50, 32, 116, 97, 114, 103, 101, + 116, 58, 52, 56, 51, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, + 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, + 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 97, 112, 112, 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 65, 112, 112, 86, + 105, 115, 105, 98, 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, + 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, + 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, + 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, + 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 112, + 204, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 9, 6, 32, 1, 16, 0, 91, 0, 170, 251, 0, 0, 0, + 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 65, 0, 50, 51, 54, + 45, 49, 53, 55, 45, 49, 51, 49, 50, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 100, + 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 110, + 116, 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, + 51, 93, 41, 0, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, + 160, 11, 33, 1, 16, 0, 40, 0, 170, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, + 170, 251, 0, 0, 0, 0, 0, 128, 171, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, + 4, 0, 45, 2, 64, 239, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 100, 177, 34, 1, 16, 0, 69, 0, + 170, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, + 43, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 99, 111, 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, + 62, 58, 52, 56, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 78, 235, 0, 0, 0, 0, + 0, 0, 161, 179, 34, 1, 16, 0, 69, 0, 170, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, + 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, 114, 111, 108, 99, 101, + 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, 0, 0, 0, 0, 4, 0, 45, + 2, 144, 238, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 216, 182, 34, 1, 16, 0, 69, 0, 170, + 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 43, 0, + 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, + 111, 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, + 52, 56, 51, 93, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 80, 15, 0, 0, 0, 0, 0, 0, 236, 0, + 0, 0, 0, 0, 0, 0, 192, 1, 0, 0, 0, 0, 0, 0, 64, 15, 0, 16, 0, 0, 0, 3, 212, 149, 193, + 240, 116, 4, 0, 0, 4, 0, 45, 2, 64, 240, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 69, 0, 170, 251, 0, 0, 0, 0, 0, 128, 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, + 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 99, 111, 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, + 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, 0, 0, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 81, + 235, 0, 0, 0, 0, 0, 0, 216, 244, 3, 0, 16, 0, 16, 0, 172, 251, 0, 0, 0, 0, 0, 128, 105, + 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 173, + 113, 5, 0, 16, 0, 135, 1, 172, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, + 18, 0, 34, 3, 66, 4, 0, 0, 73, 0, 66, 4, 73, 0, 41, 0, 66, 4, 114, 0, 239, 0, 91, 97, + 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, + 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, + 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, + 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, + 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, + 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, + 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, + 32, 34, 65, 112, 112, 86, 105, 115, 105, 98, 108, 101, 34, 32, 73, 68, 58, 50, 51, 54, + 45, 49, 53, 55, 45, 49, 51, 49, 51, 32, 116, 97, 114, 103, 101, 116, 58, 54, 52, 49, + 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, 83, 68, + 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 100, 111, + 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 97, 112, 112, + 110, 97, 112, 34, 32, 110, 97, 109, 101, 58, 34, 65, 112, 112, 86, 105, 115, 105, 98, + 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, 114, 111, 110, 109, + 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, 66, 83, + 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, 112, 108, 101, 116, + 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 112, 111, 108, 105, + 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, + 110, 62, 10, 9, 93, 62, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, + 151, 47, 6, 0, 16, 0, 121, 0, 172, 251, 0, 0, 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, + 0, 18, 0, 34, 1, 66, 4, 0, 0, 95, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 51, + 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, + 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, + 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, + 49, 93, 41, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 80, 235, 0, 0, 0, 0, + 0, 0, 75, 64, 7, 0, 16, 0, 40, 0, 172, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, + 0, 172, 251, 0, 0, 0, 0, 0, 128, 173, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, + 0, 4, 0, 45, 2, 64, 239, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 168, 154, 9, 0, 16, 0, 99, + 0, 172, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, + 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, + 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, + 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, + 4, 0, 45, 2, 240, 236, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 221, 156, 9, 0, 16, 0, 99, 0, + 172, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, + 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, + 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, + 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, + 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, + 4, 0, 45, 2, 144, 238, 31, 18, 81, 235, 0, 0, 0, 0, 0, 0, 27, 160, 9, 0, 16, 0, 99, 0, + 172, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, + 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, + 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, + 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, + 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, + 4, 0, 45, 2, 48, 14, 32, 18, 79, 235, 0, 0, 0, 0, 0, 0, 13, 17, 10, 0, 16, 0, 136, 0, + 172, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, + 67, 0, 66, 4, 67, 0, 15, 0, 66, 4, 82, 0, 16, 0, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, + 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, + 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 0, 114, + 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, + 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 0, 2, 1, 44, 0, 160, 250, 31, 18, 79, + 235, 0, 0, 0, 0, 0, 0, 126, 19, 177, 0, 16, 0, 16, 0, 174, 251, 0, 0, 0, 0, 0, 128, + 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, + 83, 78, 179, 0, 16, 0, 156, 1, 174, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, 0, 2, + 0, 18, 0, 34, 3, 66, 4, 0, 0, 73, 0, 66, 4, 73, 0, 41, 0, 66, 4, 114, 0, 4, 1, 91, 97, + 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, + 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, + 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, + 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, + 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, + 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, + 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, + 32, 34, 70, 85, 83, 66, 80, 114, 111, 99, 101, 115, 115, 87, 105, 110, 100, 111, 119, + 83, 116, 97, 116, 101, 58, 32, 118, 105, 115, 105, 98, 108, 101, 34, 32, 73, 68, 58, + 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 52, 32, 116, 97, 114, 103, 101, 116, 58, + 54, 52, 49, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, + 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, + 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 102, + 117, 115, 101, 98, 111, 97, 114, 100, 34, 32, 110, 97, 109, 101, 58, 34, 86, 105, 115, + 105, 98, 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, 114, 111, + 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, + 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, 112, 108, + 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 112, 111, + 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, 97, 116, + 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 79, + 235, 0, 0, 0, 0, 0, 0, 195, 208, 180, 0, 16, 0, 121, 0, 174, 251, 0, 0, 0, 0, 0, 128, + 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 95, 0, 50, 51, 54, 45, 49, 53, + 55, 45, 49, 51, 49, 52, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, + 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, + 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, + 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, + 48, 49, 41, 62, 58, 54, 52, 49, 93, 41, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, + 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 90, 236, 182, 0, 16, 0, 40, 0, 174, 251, 0, 0, 0, 0, + 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 174, 251, 0, 0, 0, 0, 0, 128, 175, 251, 0, 0, 0, 0, + 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 79, 235, 0, 0, 0, 0, + 0, 0, 55, 71, 186, 0, 16, 0, 99, 0, 174, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, + 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, + 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, + 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, + 52, 49, 93, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, + 234, 73, 186, 0, 16, 0, 99, 0, 174, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, + 0, 14, 0, 34, 1, 66, 4, 0, 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, + 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, + 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, + 49, 93, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, + 155, 77, 186, 0, 16, 0, 99, 0, 174, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, + 0, 14, 0, 34, 1, 66, 4, 0, 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, + 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, + 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, + 49, 93, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 235, 233, 0, 0, 0, 0, 0, 0, 113, + 197, 186, 0, 16, 0, 136, 0, 174, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, + 17, 0, 34, 3, 66, 4, 0, 0, 67, 0, 66, 4, 67, 0, 15, 0, 66, 4, 82, 0, 16, 0, 97, 112, + 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, + 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, + 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, + 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, 110, 103, 45, 97, 99, 116, 105, + 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, 97, 99, 116, 105, 118, 101, 0, + 2, 1, 44, 0, 160, 250, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 97, 148, 192, 0, 16, 0, 16, + 0, 176, 251, 0, 0, 0, 0, 0, 128, 105, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 16, 206, 31, + 18, 235, 233, 0, 0, 0, 0, 0, 0, 195, 81, 194, 0, 16, 0, 166, 1, 176, 251, 0, 0, 0, 0, + 0, 128, 82, 115, 24, 18, 1, 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 83, 0, 66, 4, 83, 0, + 41, 0, 66, 4, 124, 0, 4, 1, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, + 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, 114, + 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, + 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, + 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, + 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 60, 82, 66, 83, 65, 115, 115, + 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 111, 114, 124, 32, + 34, 70, 85, 83, 66, 80, 114, 111, 99, 101, 115, 115, 87, 105, 110, 100, 111, 119, 83, + 116, 97, 116, 101, 58, 32, 118, 105, 115, 105, 98, 108, 101, 34, 32, 73, 68, 58, 50, + 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 53, 32, 116, 97, 114, 103, 101, 116, 58, 54, + 52, 51, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 91, 10, 9, 60, 82, 66, + 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, + 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 102, + 117, 115, 101, 98, 111, 97, 114, 100, 34, 32, 110, 97, 109, 101, 58, 34, 86, 105, 115, + 105, 98, 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, 110, 118, 105, 114, 111, + 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, 34, 62, 44, 10, 9, 60, 82, + 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, 67, 111, 109, 112, 108, + 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, 101, 124, 32, 112, 111, + 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, 108, 105, 99, 97, 116, + 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 4, 0, 45, 2, 112, 204, 31, 18, 235, 233, 0, + 0, 0, 0, 0, 0, 43, 117, 195, 0, 16, 0, 131, 0, 176, 251, 0, 0, 0, 0, 0, 128, 210, 109, + 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 105, 0, 50, 51, 54, 45, 49, 53, 55, 45, + 49, 51, 49, 53, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, + 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, + 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, + 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 41, 0, 0, + 0, 0, 0, 0, 2, 1, 61, 2, 180, 201, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 2, 180, 196, 0, + 16, 0, 40, 0, 176, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 176, 251, 0, 0, + 0, 0, 0, 128, 177, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, + 64, 239, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 5, 18, 200, 0, 16, 0, 109, 0, 176, 251, 0, + 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 83, 0, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, + 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, + 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, + 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, + 52, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 6, + 21, 200, 0, 16, 0, 109, 0, 176, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, + 14, 0, 34, 1, 66, 4, 0, 0, 83, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, 120, 111, + 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, 45, 109, + 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, + 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, + 31, 18, 235, 233, 0, 0, 0, 0, 0, 0, 235, 24, 200, 0, 16, 0, 109, 0, 176, 251, 0, 0, 0, + 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 83, 0, 91, 97, 112, + 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, + 105, 116, 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, + 99, 116, 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, + 50, 55, 49, 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, + 93, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, 78, 235, 0, 0, 0, 0, 0, 0, 222, 175, 200, + 0, 16, 0, 146, 0, 176, 251, 0, 0, 0, 0, 0, 128, 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, + 3, 66, 4, 0, 0, 77, 0, 66, 4, 77, 0, 15, 0, 66, 4, 92, 0, 16, 0, 97, 112, 112, 60, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, + 104, 117, 98, 46, 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, + 104, 105, 110, 103, 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, + 46, 51, 50, 53, 57, 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, + 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, + 97, 99, 116, 105, 118, 101, 0, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 160, 250, 31, 18, 80, + 235, 0, 0, 0, 0, 0, 0, 31, 143, 205, 0, 16, 0, 16, 0, 178, 251, 0, 0, 0, 0, 0, 128, + 105, 42, 26, 18, 1, 0, 2, 0, 1, 96, 0, 0, 0, 0, 0, 0, 16, 16, 0, 0, 0, 0, 0, 0, 157, 0, + 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 0, 0, 3, 212, 212, 216, 41, + 115, 4, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 214, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, + 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, + 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 66, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 66, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, + 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 2, 1, 21, 2, + 208, 110, 164, 6, 214, 233, 0, 0, 0, 0, 0, 0, 97, 87, 224, 1, 16, 0, 36, 0, 208, 250, + 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 208, 250, 0, 0, 0, 0, 0, 128, 92, 228, 0, + 0, 0, 0, 0, 128, 147, 21, 160, 6, 0, 0, 0, 0, 4, 0, 5, 2, 240, 120, 164, 6, 214, 233, + 0, 0, 0, 0, 0, 0, 48, 118, 227, 1, 16, 0, 125, 0, 92, 228, 0, 0, 0, 0, 0, 128, 235, 61, + 163, 6, 83, 0, 34, 2, 0, 8, 135, 16, 0, 0, 122, 136, 29, 9, 66, 4, 0, 0, 93, 0, 91, + 120, 112, 99, 115, 101, 114, 118, 105, 99, 101, 60, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 67, 114, 121, 112, 116, 111, 84, 111, 107, 101, 110, 75, 105, 116, 46, + 112, 105, 118, 116, 111, 107, 101, 110, 40, 91, 100, 97, 101, 109, 111, 110, 60, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 116, 107, 100, 40, 53, 48, 49, 41, 62, + 58, 52, 53, 50, 93, 41, 40, 53, 48, 49, 41, 62, 58, 52, 50, 51, 49, 93, 0, 0, 0, 0, 4, + 0, 5, 2, 160, 108, 164, 6, 214, 233, 0, 0, 0, 0, 0, 0, 5, 22, 228, 1, 16, 0, 22, 0, 92, + 228, 0, 0, 0, 0, 0, 128, 86, 10, 162, 6, 84, 0, 0, 1, 0, 4, 135, 16, 0, 0, 0, 0, 2, 1, + 21, 2, 208, 110, 164, 6, 27, 234, 0, 0, 0, 0, 0, 0, 122, 73, 235, 1, 16, 0, 36, 0, 210, + 250, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 210, 250, 0, 0, 0, 0, 0, 128, 93, + 228, 0, 0, 0, 0, 0, 128, 147, 21, 160, 6, 0, 0, 0, 0, 4, 0, 5, 2, 160, 108, 164, 6, 27, + 234, 0, 0, 0, 0, 0, 0, 220, 179, 235, 1, 16, 0, 22, 0, 93, 228, 0, 0, 0, 0, 0, 128, 86, + 10, 162, 6, 84, 0, 0, 1, 0, 4, 135, 16, 0, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 27, + 234, 0, 0, 0, 0, 0, 0, 85, 177, 132, 23, 16, 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, + 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 33, 0, 0, 0, 0, 0, 0, 0, 0, 8, 34, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, 99, + 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 1, 10, 2, 192, 184, 0, 0, 214, 233, 0, 0, 0, + 0, 0, 0, 77, 169, 38, 24, 16, 0, 36, 0, 181, 68, 0, 0, 161, 247, 205, 111, 229, 209, + 49, 1, 157, 239, 1, 129, 177, 149, 3, 123, 16, 0, 0, 2, 0, 4, 0, 0, 0, 0, 0, 4, 2, 0, + 0, 0, 0, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 252, 234, 0, 0, 0, 0, 0, 0, 248, 216, + 189, 28, 16, 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, + 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 103, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 231, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, + 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, + 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 5, 235, 0, 0, 0, 0, 0, 0, 55, 159, 71, 29, 16, 0, 94, + 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, + 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 66, 0, 0, 0, 0, 0, 0, 0, 0, 8, + 66, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, + 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, 2, 0, + 66, 15, 13, 4, 235, 0, 0, 0, 0, 0, 0, 43, 171, 46, 42, 16, 0, 94, 0, 122, 179, 12, 13, + 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, + 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 97, 0, 0, 0, 0, 0, 0, 0, 0, 8, 98, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, + 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 214, 233, 0, + 0, 0, 0, 0, 0, 120, 0, 199, 128, 16, 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, + 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, + 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, + 110, 116, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 214, 233, 0, 0, 0, 0, 0, 0, 220, 211, + 147, 167, 16, 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, + 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 1, + 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, + 4, 0, 44, 2, 0, 66, 15, 13, 39, 234, 0, 0, 0, 0, 0, 0, 73, 20, 207, 253, 16, 0, 94, 0, + 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, + 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, + 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, + 13, 1, 235, 0, 0, 0, 0, 0, 0, 113, 228, 210, 8, 17, 0, 94, 0, 122, 179, 12, 13, 2, 0, + 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, + 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, 99, + 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 1, 235, 0, 0, 0, 0, + 0, 0, 95, 90, 187, 77, 17, 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, + 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, + 116, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 5, 235, 0, 0, 0, 0, 0, 0, 143, 138, 66, 108, + 17, 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, + 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 33, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, + 0, 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, + 2, 0, 66, 15, 13, 27, 234, 0, 0, 0, 0, 0, 0, 106, 126, 165, 122, 17, 0, 94, 0, 122, + 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, + 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 33, 0, 0, 0, 0, 0, 0, 0, 0, 8, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 100, 105, + 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, + 13, 252, 234, 0, 0, 0, 0, 0, 0, 150, 168, 131, 126, 17, 0, 94, 0, 122, 179, 12, 13, 2, + 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, + 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 249, 234, 0, 0, + 0, 0, 0, 0, 130, 250, 183, 132, 17, 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, + 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, + 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, + 110, 116, 0, 0, 0, 4, 1, 4, 2, 16, 15, 98, 5, 136, 3, 0, 0, 0, 0, 0, 0, 78, 125, 10, + 174, 17, 0, 60, 0, 6, 70, 70, 5, 3, 0, 34, 4, 0, 4, 3, 220, 1, 0, 32, 4, 0, 0, 24, 0, + 0, 4, 108, 7, 0, 0, 0, 8, 25, 0, 0, 0, 0, 0, 0, 0, 82, 101, 109, 111, 118, 101, 87, + 105, 110, 100, 111, 119, 115, 70, 114, 111, 109, 83, 112, 97, 99, 101, 115, 0, 0, 0, 0, + 0, 4, 1, 4, 2, 64, 14, 98, 5, 136, 3, 0, 0, 0, 0, 0, 0, 248, 150, 10, 174, 17, 0, 60, + 0, 182, 104, 70, 5, 3, 0, 34, 4, 0, 4, 3, 220, 1, 0, 32, 4, 0, 0, 24, 0, 0, 4, 108, 7, + 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 0, 82, 101, 109, 111, 118, 101, 87, 105, 110, 100, + 111, 119, 115, 70, 114, 111, 109, 83, 112, 97, 99, 101, 115, 0, 0, 0, 0, 0, 4, 1, 4, 2, + 16, 15, 98, 5, 136, 3, 0, 0, 0, 0, 0, 0, 133, 138, 11, 174, 17, 0, 60, 0, 6, 70, 70, 5, + 3, 0, 34, 4, 0, 4, 3, 220, 1, 0, 32, 4, 0, 0, 24, 0, 0, 4, 110, 7, 0, 0, 0, 8, 25, 0, + 0, 0, 0, 0, 0, 0, 82, 101, 109, 111, 118, 101, 87, 105, 110, 100, 111, 119, 115, 70, + 114, 111, 109, 83, 112, 97, 99, 101, 115, 0, 0, 0, 0, 0, 4, 1, 4, 2, 64, 14, 98, 5, + 136, 3, 0, 0, 0, 0, 0, 0, 254, 155, 11, 174, 17, 0, 60, 0, 182, 104, 70, 5, 3, 0, 34, + 4, 0, 4, 3, 220, 1, 0, 32, 4, 0, 0, 24, 0, 0, 4, 110, 7, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, + 0, 0, 82, 101, 109, 111, 118, 101, 87, 105, 110, 100, 111, 119, 115, 70, 114, 111, 109, + 83, 112, 97, 99, 101, 115, 0, 0, 0, 0, 0, 4, 1, 4, 2, 16, 15, 98, 5, 136, 3, 0, 0, 0, + 0, 0, 0, 98, 0, 74, 174, 17, 0, 52, 0, 6, 70, 70, 5, 3, 0, 34, 4, 0, 4, 3, 220, 1, 0, + 32, 4, 0, 0, 16, 0, 0, 4, 108, 7, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 0, 84, 101, 114, + 109, 105, 110, 97, 116, 101, 87, 105, 110, 100, 111, 119, 0, 0, 0, 0, 0, 4, 1, 4, 2, + 16, 15, 98, 5, 136, 3, 0, 0, 0, 0, 0, 0, 132, 36, 111, 174, 17, 0, 52, 0, 6, 70, 70, 5, + 3, 0, 34, 4, 0, 4, 3, 220, 1, 0, 32, 4, 0, 0, 16, 0, 0, 4, 110, 7, 0, 0, 0, 8, 1, 0, 0, + 0, 0, 0, 0, 0, 84, 101, 114, 109, 105, 110, 97, 116, 101, 87, 105, 110, 100, 111, 119, + 0, 0, 0, 0, 0, 4, 1, 4, 2, 176, 203, 97, 5, 136, 3, 0, 0, 0, 0, 0, 0, 104, 116, 218, + 174, 17, 0, 75, 0, 77, 15, 55, 5, 3, 0, 34, 5, 0, 4, 11, 79, 3, 0, 32, 4, 0, 0, 26, 0, + 0, 4, 40, 5, 0, 0, 32, 4, 26, 0, 7, 0, 32, 4, 33, 0, 4, 0, 83, 101, 116, 87, 105, 110, + 100, 111, 119, 72, 97, 115, 75, 101, 121, 65, 112, 112, 101, 97, 114, 97, 110, 99, 101, + 0, 97, 99, 116, 105, 118, 101, 0, 107, 101, 121, 0, 0, 0, 0, 0, 0, 4, 1, 4, 2, 176, + 203, 97, 5, 136, 3, 0, 0, 0, 0, 0, 0, 88, 160, 218, 174, 17, 0, 77, 0, 77, 15, 55, 5, + 3, 0, 34, 5, 0, 4, 11, 79, 3, 0, 32, 4, 0, 0, 27, 0, 0, 4, 40, 5, 0, 0, 32, 4, 27, 0, + 7, 0, 32, 4, 34, 0, 5, 0, 83, 101, 116, 87, 105, 110, 100, 111, 119, 72, 97, 115, 77, + 97, 105, 110, 65, 112, 112, 101, 97, 114, 97, 110, 99, 101, 0, 97, 99, 116, 105, 118, + 101, 0, 109, 97, 105, 110, 0, 0, 0, 0, 4, 0, 44, 2, 16, 221, 120, 8, 136, 3, 0, 0, 0, + 0, 0, 0, 199, 37, 5, 176, 17, 0, 53, 0, 92, 172, 120, 8, 1, 0, 2, 0, 75, 0, 35, 4, 65, + 4, 0, 0, 0, 0, 0, 4, 75, 0, 0, 0, 64, 4, 0, 0, 9, 0, 64, 4, 9, 0, 8, 0, 111, 99, 99, + 108, 117, 100, 101, 100, 0, 118, 105, 115, 105, 98, 108, 101, 0, 0, 0, 0, 4, 0, 44, 2, + 128, 221, 120, 8, 136, 3, 0, 0, 0, 0, 0, 0, 22, 57, 5, 176, 17, 0, 32, 0, 2, 182, 120, + 8, 1, 0, 2, 0, 75, 0, 35, 2, 65, 4, 0, 0, 0, 0, 64, 4, 0, 0, 8, 0, 118, 105, 115, 105, + 98, 108, 101, 0, 4, 0, 44, 2, 16, 221, 120, 8, 136, 3, 0, 0, 0, 0, 0, 0, 172, 189, 5, + 176, 17, 0, 53, 0, 92, 172, 120, 8, 1, 0, 2, 0, 75, 0, 35, 4, 65, 4, 0, 0, 0, 0, 0, 4, + 69, 0, 0, 0, 64, 4, 0, 0, 9, 0, 64, 4, 9, 0, 8, 0, 111, 99, 99, 108, 117, 100, 101, + 100, 0, 118, 105, 115, 105, 98, 108, 101, 0, 0, 0, 0, 4, 0, 44, 2, 16, 221, 120, 8, + 136, 3, 0, 0, 0, 0, 0, 0, 249, 207, 5, 176, 17, 0, 53, 0, 92, 172, 120, 8, 1, 0, 2, 0, + 75, 0, 35, 4, 65, 4, 0, 0, 0, 0, 0, 4, 40, 5, 0, 0, 64, 4, 0, 0, 9, 0, 64, 4, 9, 0, 8, + 0, 111, 99, 99, 108, 117, 100, 101, 100, 0, 118, 105, 115, 105, 98, 108, 101, 0, 0, 0, + 0, 4, 0, 44, 2, 128, 221, 120, 8, 136, 3, 0, 0, 0, 0, 0, 0, 67, 214, 5, 176, 17, 0, 32, + 0, 2, 182, 120, 8, 1, 0, 2, 0, 75, 0, 35, 2, 65, 4, 0, 0, 0, 0, 64, 4, 0, 0, 8, 0, 118, + 105, 115, 105, 98, 108, 101, 0, 4, 0, 44, 2, 0, 66, 15, 13, 4, 235, 0, 0, 0, 0, 0, 0, + 176, 97, 130, 179, 17, 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, + 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 99, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 98, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, + 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, + 0, 0, 0, 4, 0, 44, 2, 0, 66, 15, 13, 4, 235, 0, 0, 0, 0, 0, 0, 119, 126, 86, 194, 17, + 0, 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, + 1, 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, + 0, 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, 2, + 16, 221, 120, 8, 136, 3, 0, 0, 0, 0, 0, 0, 165, 221, 149, 199, 17, 0, 49, 0, 92, 172, + 120, 8, 1, 0, 2, 0, 75, 0, 35, 4, 65, 4, 0, 0, 0, 0, 0, 4, 103, 0, 0, 0, 64, 4, 0, 0, + 5, 0, 64, 4, 5, 0, 8, 0, 110, 111, 110, 101, 0, 118, 105, 115, 105, 98, 108, 101, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 0, 44, 2, 128, 221, 120, 8, 136, 3, 0, 0, 0, 0, 0, 0, 6, 244, 149, + 199, 17, 0, 32, 0, 2, 182, 120, 8, 1, 0, 2, 0, 75, 0, 35, 2, 65, 4, 0, 0, 0, 0, 64, 4, + 0, 0, 8, 0, 118, 105, 115, 105, 98, 108, 101, 0, 4, 0, 44, 2, 16, 221, 120, 8, 136, 3, + 0, 0, 0, 0, 0, 0, 214, 49, 151, 199, 17, 0, 49, 0, 92, 172, 120, 8, 1, 0, 2, 0, 75, 0, + 35, 4, 65, 4, 0, 0, 0, 0, 0, 4, 100, 0, 0, 0, 64, 4, 0, 0, 5, 0, 64, 4, 5, 0, 8, 0, + 110, 111, 110, 101, 0, 118, 105, 115, 105, 98, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, + 44, 2, 128, 221, 120, 8, 136, 3, 0, 0, 0, 0, 0, 0, 32, 62, 151, 199, 17, 0, 32, 0, 2, + 182, 120, 8, 1, 0, 2, 0, 75, 0, 35, 2, 65, 4, 0, 0, 0, 0, 64, 4, 0, 0, 8, 0, 118, 105, + 115, 105, 98, 108, 101, 0, 4, 0, 44, 2, 16, 221, 120, 8, 136, 3, 0, 0, 0, 0, 0, 0, 52, + 232, 155, 199, 17, 0, 49, 0, 92, 172, 120, 8, 1, 0, 2, 0, 75, 0, 35, 4, 65, 4, 0, 0, 0, + 0, 0, 4, 105, 0, 0, 0, 64, 4, 0, 0, 5, 0, 64, 4, 5, 0, 8, 0, 110, 111, 110, 101, 0, + 118, 105, 115, 105, 98, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 44, 2, 128, 221, 120, + 8, 136, 3, 0, 0, 0, 0, 0, 0, 185, 252, 155, 199, 17, 0, 32, 0, 2, 182, 120, 8, 1, 0, 2, + 0, 75, 0, 35, 2, 65, 4, 0, 0, 0, 0, 64, 4, 0, 0, 8, 0, 118, 105, 115, 105, 98, 108, + 101, 0, 4, 0, 44, 2, 0, 66, 15, 13, 27, 234, 0, 0, 0, 0, 0, 0, 24, 250, 9, 201, 17, 0, + 94, 0, 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, + 0, 32, 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 99, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 98, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, + 100, 105, 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 4, 0, 44, 2, 0, + 66, 15, 13, 4, 235, 0, 0, 0, 0, 0, 0, 15, 141, 195, 228, 17, 0, 94, 0, 122, 179, 12, + 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, 4, 2, 0, 14, 0, + 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, 115, 112, 97, + 116, 99, 104, 69, 118, 101, 110, 116, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 184, 15, 0, 0, + 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 192, 1, 0, 0, 0, 0, 0, 0, 168, 15, 0, 16, 0, 0, + 0, 3, 242, 224, 144, 241, 116, 4, 0, 0, 4, 0, 45, 2, 16, 206, 31, 18, 80, 235, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 16, 0, 157, 1, 178, 251, 0, 0, 0, 0, 0, 128, 82, 115, 24, 18, 1, + 0, 2, 0, 18, 0, 34, 3, 66, 4, 0, 0, 74, 0, 66, 4, 74, 0, 41, 0, 66, 4, 115, 0, 4, 1, + 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, + 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, + 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, + 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 0, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, 100, + 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 60, + 82, 66, 83, 65, 115, 115, 101, 114, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, + 112, 116, 111, 114, 124, 32, 34, 70, 85, 83, 66, 80, 114, 111, 99, 101, 115, 115, 87, + 105, 110, 100, 111, 119, 83, 116, 97, 116, 101, 58, 32, 118, 105, 115, 105, 98, 108, + 101, 34, 32, 73, 68, 58, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 54, 32, 116, 97, + 114, 103, 101, 116, 58, 54, 52, 55, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, + 58, 91, 10, 9, 60, 82, 66, 83, 68, 111, 109, 97, 105, 110, 65, 116, 116, 114, 105, 98, + 117, 116, 101, 124, 32, 100, 111, 109, 97, 105, 110, 58, 34, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 102, 117, 115, 101, 98, 111, 97, 114, 100, 34, 32, 110, 97, 109, + 101, 58, 34, 86, 105, 115, 105, 98, 108, 101, 34, 32, 115, 111, 117, 114, 99, 101, 69, + 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 58, 34, 40, 110, 117, 108, 108, 41, + 34, 62, 44, 10, 9, 60, 82, 66, 83, 65, 99, 113, 117, 105, 115, 105, 116, 105, 111, 110, + 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 65, 116, 116, 114, 105, 98, 117, 116, + 101, 124, 32, 112, 111, 108, 105, 99, 121, 58, 65, 102, 116, 101, 114, 65, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 62, 10, 9, 93, 62, 0, 0, 0, 0, 4, 0, 45, 2, 112, + 204, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 190, 93, 1, 0, 16, 0, 122, 0, 178, 251, 0, 0, + 0, 0, 0, 128, 210, 109, 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 96, 0, 50, 51, + 54, 45, 49, 53, 55, 45, 49, 51, 49, 54, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, + 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, + 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, + 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, + 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 41, 0, 0, 0, 0, 0, 0, 0, 2, + 1, 61, 2, 180, 201, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 61, 173, 2, 0, 16, 0, 40, 0, + 178, 251, 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 178, 251, 0, 0, 0, 0, 0, 128, + 179, 251, 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, + 78, 235, 0, 0, 0, 0, 0, 0, 224, 146, 5, 0, 16, 0, 100, 0, 178, 251, 0, 0, 0, 0, 0, 128, + 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, 97, 112, 112, 60, + 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, + 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, + 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, + 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 0, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, + 18, 78, 235, 0, 0, 0, 0, 0, 0, 21, 150, 5, 0, 16, 0, 100, 0, 178, 251, 0, 0, 0, 0, 0, + 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, 97, 112, 112, + 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, + 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, + 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, + 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 0, 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, + 18, 78, 235, 0, 0, 0, 0, 0, 0, 168, 153, 5, 0, 16, 0, 100, 0, 178, 251, 0, 0, 0, 0, 0, + 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 74, 0, 91, 97, 112, 112, + 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, + 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, + 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, + 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, 0, 0, 0, 0, 0, 4, 0, 45, 2, 48, 14, 32, 18, + 78, 235, 0, 0, 0, 0, 0, 0, 130, 254, 5, 0, 16, 0, 137, 0, 178, 251, 0, 0, 0, 0, 0, 128, + 201, 16, 27, 18, 1, 0, 2, 0, 17, 0, 34, 3, 66, 4, 0, 0, 68, 0, 66, 4, 68, 0, 15, 0, 66, + 4, 83, 0, 16, 0, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, + 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, 101, 115, + 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, 53, 55, + 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 0, 114, 117, 110, 110, 105, + 110, 103, 45, 97, 99, 116, 105, 118, 101, 0, 85, 115, 101, 114, 73, 110, 116, 101, 114, + 97, 99, 116, 105, 118, 101, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 192, 250, 31, 18, 79, + 235, 0, 0, 0, 0, 0, 0, 182, 236, 215, 28, 16, 0, 16, 0, 180, 251, 0, 0, 0, 0, 0, 128, + 251, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, + 38, 57, 216, 28, 16, 0, 168, 0, 180, 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, + 0, 18, 0, 34, 2, 66, 4, 0, 0, 95, 0, 66, 4, 95, 0, 41, 0, 50, 51, 54, 45, 49, 53, 55, + 45, 49, 51, 49, 51, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, + 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, + 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, + 48, 49, 41, 62, 58, 54, 52, 49, 93, 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, + 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, + 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 2, 1, 44, 0, 192, 250, 31, + 18, 79, 235, 0, 0, 0, 0, 0, 0, 159, 224, 216, 28, 16, 0, 16, 0, 181, 251, 0, 0, 0, 0, + 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 79, 235, 0, 0, 0, + 0, 0, 0, 197, 8, 217, 28, 16, 0, 138, 0, 181, 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, + 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 65, 0, 66, 4, 65, 0, 41, 0, 50, 51, 54, 45, 49, + 53, 55, 45, 49, 51, 49, 50, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, + 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, + 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, + 49, 53, 55, 93, 0, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 192, 250, 31, 18, 79, 235, 0, 0, 0, + 0, 0, 0, 64, 236, 217, 28, 16, 0, 16, 0, 182, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, + 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 169, 16, 218, 28, + 16, 0, 178, 0, 182, 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, + 66, 4, 0, 0, 105, 0, 66, 4, 105, 0, 41, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, + 49, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, + 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, + 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, + 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 41, 0, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, 100, + 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 0, 0, + 0, 0, 0, 0, 2, 1, 44, 0, 192, 250, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 35, 113, 219, 28, + 16, 0, 16, 0, 183, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, 2, + 112, 206, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 223, 146, 219, 28, 16, 0, 169, 0, 183, + 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 96, 0, + 66, 4, 96, 0, 41, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 48, 32, 40, 116, 97, + 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, + 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, + 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, + 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, + 49, 53, 55, 93, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 44, 0, 192, 250, 31, 18, 79, 235, 0, 0, + 0, 0, 0, 0, 220, 155, 213, 30, 16, 0, 16, 0, 184, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, + 18, 1, 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 72, 10, 214, + 30, 16, 0, 168, 0, 184, 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, + 34, 2, 66, 4, 0, 0, 95, 0, 66, 4, 95, 0, 41, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, + 49, 52, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, + 105, 118, 101, 45, 115, 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, + 51, 53, 48, 52, 52, 52, 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, + 54, 52, 49, 93, 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, + 56, 41, 62, 58, 49, 53, 55, 93, 0, 2, 1, 44, 0, 192, 250, 31, 18, 79, 235, 0, 0, 0, 0, + 0, 0, 36, 73, 231, 30, 16, 0, 16, 0, 185, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, + 0, 2, 0, 4, 0, 45, 2, 112, 206, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 232, 164, 231, 30, + 16, 0, 178, 0, 185, 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, + 66, 4, 0, 0, 105, 0, 66, 4, 105, 0, 41, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, + 53, 32, 40, 116, 97, 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, + 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, + 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, + 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 58, 54, 52, 51, 93, 41, 0, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 87, 105, 110, 100, + 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, 49, 53, 55, 93, 0, 0, 0, + 0, 0, 0, 0, 2, 1, 44, 0, 192, 250, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 130, 139, 232, + 30, 16, 0, 16, 0, 186, 251, 0, 0, 0, 0, 0, 128, 251, 42, 26, 18, 1, 0, 2, 0, 4, 0, 45, + 2, 112, 206, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 172, 203, 232, 30, 16, 0, 169, 0, 186, + 251, 0, 0, 0, 0, 0, 128, 56, 132, 24, 18, 1, 0, 2, 0, 18, 0, 34, 2, 66, 4, 0, 0, 96, 0, + 66, 4, 96, 0, 41, 0, 50, 51, 54, 45, 49, 53, 55, 45, 49, 51, 49, 54, 32, 40, 116, 97, + 114, 103, 101, 116, 58, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, 108, 111, 117, 100, 46, 100, + 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, 46, 50, 55, 54, 53, 49, 56, + 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, 41, 62, 58, 54, 52, 55, 93, + 41, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, + 46, 87, 105, 110, 100, 111, 119, 83, 101, 114, 118, 101, 114, 40, 56, 56, 41, 62, 58, + 49, 53, 55, 93, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 45, 2, 160, 200, 31, 18, 79, 235, 0, 0, + 0, 0, 0, 0, 111, 202, 27, 35, 16, 0, 103, 0, 180, 251, 0, 0, 0, 0, 0, 128, 1, 44, 24, + 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 77, 0, 97, 112, 112, 60, 97, 112, 112, 108, + 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 103, 105, 116, 104, 117, 98, 46, + 120, 111, 114, 45, 103, 97, 116, 101, 46, 115, 121, 110, 99, 116, 104, 105, 110, 103, + 45, 109, 97, 99, 111, 115, 120, 46, 51, 50, 53, 57, 50, 50, 55, 49, 46, 51, 50, 53, 57, + 50, 50, 55, 54, 40, 53, 48, 49, 41, 62, 0, 0, 4, 0, 45, 2, 160, 200, 31, 18, 79, 235, + 0, 0, 0, 0, 0, 0, 218, 223, 27, 35, 16, 0, 94, 0, 180, 251, 0, 0, 0, 0, 0, 128, 1, 44, + 24, 18, 1, 0, 2, 0, 18, 0, 34, 1, 66, 4, 0, 0, 68, 0, 97, 112, 112, 60, 97, 112, 112, + 108, 105, 99, 97, 116, 105, 111, 110, 46, 99, 111, 109, 46, 110, 101, 120, 116, 99, + 108, 111, 117, 100, 46, 100, 101, 115, 107, 116, 111, 112, 99, 108, 105, 101, 110, 116, + 46, 50, 55, 54, 53, 49, 56, 53, 55, 46, 51, 50, 50, 53, 48, 56, 52, 53, 40, 53, 48, 49, + 41, 62, 0, 0, 0, 4, 0, 45, 2, 160, 200, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 183, 240, + 27, 35, 16, 0, 93, 0, 180, 251, 0, 0, 0, 0, 0, 128, 1, 44, 24, 18, 1, 0, 2, 0, 18, 0, + 34, 1, 66, 4, 0, 0, 67, 0, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, + 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, + 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 0, 0, 0, 0, 2, 1, 61, 2, + 180, 201, 31, 18, 79, 235, 0, 0, 0, 0, 0, 0, 35, 171, 28, 35, 16, 0, 40, 0, 180, 251, + 0, 0, 0, 0, 0, 128, 236, 0, 0, 0, 0, 0, 0, 0, 180, 251, 0, 0, 0, 0, 0, 128, 187, 251, + 0, 0, 0, 0, 0, 128, 64, 63, 24, 18, 1, 0, 2, 0, 2, 1, 61, 2, 96, 200, 31, 18, 79, 235, + 0, 0, 0, 0, 0, 0, 23, 50, 33, 35, 16, 0, 40, 0, 180, 251, 0, 0, 0, 0, 0, 128, 236, 0, + 0, 0, 0, 0, 0, 0, 180, 251, 0, 0, 0, 0, 0, 128, 188, 251, 0, 0, 0, 0, 0, 128, 7, 35, + 24, 18, 1, 0, 2, 0, 4, 0, 45, 2, 64, 239, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 56, 178, + 36, 35, 16, 0, 69, 0, 188, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, + 0, 34, 1, 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, + 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, + 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 240, 236, 31, + 18, 80, 235, 0, 0, 0, 0, 0, 0, 150, 181, 36, 35, 16, 0, 69, 0, 188, 251, 0, 0, 0, 0, 0, + 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, + 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, + 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, + 0, 0, 0, 0, 4, 0, 45, 2, 144, 238, 31, 18, 80, 235, 0, 0, 0, 0, 0, 0, 13, 186, 36, 35, + 16, 0, 69, 0, 188, 251, 0, 0, 0, 0, 0, 128, 74, 210, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, + 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, 109, 111, 110, 60, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 99, 111, 110, 116, 114, 111, 108, 99, 101, 110, 116, 101, 114, 40, + 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, 0, 0, 0, 0, 4, 0, 45, 2, 64, 240, 31, 18, 80, + 235, 0, 0, 0, 0, 0, 0, 242, 200, 36, 35, 16, 0, 69, 0, 188, 251, 0, 0, 0, 0, 0, 128, + 195, 214, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, 0, 43, 0, 91, 100, 97, 101, 109, + 111, 110, 60, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 99, 111, 110, 116, 114, + 111, 108, 99, 101, 110, 116, 101, 114, 40, 53, 48, 49, 41, 62, 58, 52, 56, 51, 93, 0, + 0, 0, 0, 4, 0, 45, 2, 64, 239, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 183, 221, 36, 35, 16, + 0, 99, 0, 188, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, + 4, 0, 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, + 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, + 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, + 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, + 0, 0, 4, 0, 45, 2, 240, 236, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 55, 225, 36, 35, 16, 0, + 99, 0, 188, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, + 0, 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, + 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, + 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, + 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, + 1, 96, 0, 0, 0, 0, 0, 0, 152, 0, 0, 0, 0, 0, 0, 0, 133, 16, 0, 0, 0, 0, 0, 0, 157, 38, + 0, 0, 0, 0, 0, 0, 136, 0, 0, 16, 0, 0, 0, 2, 42, 188, 25, 14, 104, 4, 0, 0, 2, 1, 4, 0, + 240, 243, 53, 0, 176, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 12, 0, 176, 249, 0, 0, + 0, 0, 0, 128, 163, 133, 51, 0, 0, 0, 0, 0, 2, 1, 4, 0, 32, 250, 53, 0, 177, 232, 0, 0, + 0, 0, 0, 0, 209, 67, 85, 0, 16, 0, 12, 0, 177, 249, 0, 0, 0, 0, 0, 128, 237, 115, 51, + 0, 0, 0, 0, 0, 2, 1, 4, 0, 48, 57, 126, 0, 179, 232, 0, 0, 0, 0, 0, 0, 40, 101, 197, 1, + 16, 0, 12, 0, 178, 249, 0, 0, 0, 0, 0, 128, 105, 67, 61, 0, 0, 0, 0, 0, + ]; + let (mut data, firehose) = + FirehosePreamble::parse_firehose_preamble(&test_firehose_data).unwrap(); + assert_eq!(firehose.chunk_tag, 0x6001); + assert_eq!(firehose.chunk_sub_tag, 0); + assert_eq!(firehose.chunk_data_size, 4032); + assert_eq!(firehose.first_number_proc_id, 483); + assert_eq!(firehose.second_number_proc_id, 1123); + assert_eq!(firehose.collapsed, 0); + assert_eq!(firehose.ttl, 0); + assert_eq!(firehose.unknown, [0, 0]); + assert_eq!(firehose.public_data_size, 4016); + assert_eq!(firehose.private_data_virtual_offset, 4096); + assert_eq!(firehose.unkonwn2, 0); + assert_eq!(firehose.unknown3, 768); + assert_eq!(firehose.base_continous_time, 4197166166425); + + let mut firehouse_result_count = firehose.public_data.len(); + while data.len() != 0 { + let (test_data, firehose) = FirehosePreamble::parse_firehose_preamble(&data).unwrap(); + data = test_data; + firehouse_result_count += firehose.public_data.len(); + } + assert_eq!(firehouse_result_count, 371) + } + + #[test] + fn test_parse_firehose() { + let test_firehose_data = [ + 4, 0, 45, 2, 64, 239, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 183, 221, 36, 35, 16, 0, 99, + 0, 188, 251, 0, 0, 0, 0, 0, 128, 198, 202, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, + 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, + 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, + 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, + 4, 0, 45, 2, 240, 236, 31, 18, 78, 235, 0, 0, 0, 0, 0, 0, 55, 225, 36, 35, 16, 0, 99, + 0, 188, 251, 0, 0, 0, 0, 0, 128, 115, 205, 25, 18, 1, 0, 2, 0, 14, 0, 34, 1, 66, 4, 0, + 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 46, + 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, 101, 101, 46, + 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, 46, 50, 57, + 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, 0, 0, 0, 0, 0, + ]; + + let (_, firehose) = FirehosePreamble::parse_firehose(&test_firehose_data).unwrap(); + assert_eq!(firehose.unknown_log_activity_type, 4); + assert_eq!(firehose.unknown_log_type, 0); + assert_eq!(firehose.flags, 557); + assert_eq!(firehose.format_string_location, 304082752); + assert_eq!(firehose.thread_id, 60238); + assert_eq!(firehose.continous_time_delta, 589618615); + assert_eq!(firehose.continous_time_delta_upper, 16); + assert_eq!(firehose.data_size, 99); + assert_eq!(firehose.firehose_non_activity.unknown_activity_id, 64444); + assert_eq!(firehose.firehose_non_activity.unknown_sentinal, 2147483648); + assert_eq!(firehose.firehose_non_activity.private_strings_offset, 0); + assert_eq!(firehose.firehose_non_activity.private_strings_size, 0); + assert_eq!(firehose.firehose_non_activity.unknown_message_string_ref, 0); + assert_eq!( + firehose.firehose_non_activity.firehose_formatters.main_exe, + false + ); + + assert_eq!(firehose.firehose_non_activity.subsystem_value, 14); + assert_eq!(firehose.firehose_non_activity.ttl_value, 0); + assert_eq!(firehose.firehose_non_activity.data_ref_value, 0); + assert_eq!( + firehose + .firehose_non_activity + .firehose_formatters + .large_shared_cache, + 2 + ); + assert_eq!( + firehose + .firehose_non_activity + .firehose_formatters + .has_large_offset, + 1 + ); + assert_eq!(firehose.firehose_non_activity.unknown_pc_id, 303680198); + assert_eq!(firehose.unknown_item, 34); + assert_eq!(firehose.number_items, 1); + assert_eq!( + firehose.message.item_info[0].message_strings, + "[app:641]" + ); + } + + #[test] + fn test_parse_firehose_private_data_zeros() { + let data = [ + 1, 96, 0, 0, 0, 0, 0, 0, 170, 2, 0, 0, 0, 0, 0, 0, 59, 37, 18, 0, 0, 0, 0, 0, 70, 249, + 40, 0, 0, 1, 0, 0, 152, 2, 254, 15, 0, 0, 0, 2, 131, 242, 63, 252, 246, 138, 9, 0, 2, + 1, 4, 0, 240, 67, 56, 0, 174, 149, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 12, 0, 144, + 131, 160, 0, 0, 0, 0, 128, 214, 201, 53, 0, 0, 0, 0, 0, 2, 1, 21, 2, 16, 85, 128, 0, + 175, 149, 170, 0, 0, 0, 0, 0, 198, 111, 97, 0, 16, 0, 36, 0, 116, 131, 160, 0, 0, 0, 0, + 128, 58, 37, 18, 0, 0, 0, 0, 0, 116, 131, 160, 0, 0, 0, 0, 128, 145, 131, 160, 0, 0, 0, + 0, 128, 217, 143, 63, 0, 0, 0, 0, 0, 2, 1, 21, 2, 32, 74, 56, 0, 175, 149, 170, 0, 0, + 0, 0, 0, 126, 204, 117, 0, 16, 0, 36, 0, 116, 131, 160, 0, 0, 0, 0, 128, 58, 37, 18, 0, + 0, 0, 0, 0, 116, 131, 160, 0, 0, 0, 0, 128, 146, 131, 160, 0, 0, 0, 0, 128, 29, 184, + 53, 0, 0, 0, 0, 0, 4, 0, 5, 2, 128, 122, 77, 2, 175, 149, 170, 0, 0, 0, 0, 0, 218, 39, + 146, 0, 16, 0, 106, 0, 116, 131, 160, 0, 0, 0, 0, 128, 5, 31, 56, 2, 18, 0, 34, 2, 66, + 4, 0, 0, 39, 0, 66, 4, 39, 0, 39, 0, 47, 83, 121, 115, 116, 101, 109, 47, 76, 105, 98, + 114, 97, 114, 121, 47, 83, 101, 99, 117, 114, 105, 116, 121, 47, 108, 100, 97, 112, + 100, 108, 46, 98, 117, 110, 100, 108, 101, 0, 123, 56, 55, 49, 57, 49, 99, 97, 54, 45, + 48, 102, 99, 57, 45, 49, 49, 100, 52, 45, 56, 52, 57, 97, 45, 48, 48, 48, 53, 48, 50, + 98, 53, 50, 49, 50, 50, 125, 0, 0, 0, 0, 0, 0, 0, 4, 0, 5, 2, 128, 122, 77, 2, 175, + 149, 170, 0, 0, 0, 0, 0, 22, 10, 147, 0, 16, 0, 113, 0, 116, 131, 160, 0, 0, 0, 0, 128, + 5, 31, 56, 2, 18, 0, 34, 2, 66, 4, 0, 0, 46, 0, 66, 4, 46, 0, 39, 0, 47, 83, 121, 115, + 116, 101, 109, 47, 76, 105, 98, 114, 97, 114, 121, 47, 70, 114, 97, 109, 101, 119, 111, + 114, 107, 115, 47, 83, 101, 99, 117, 114, 105, 116, 121, 46, 102, 114, 97, 109, 101, + 119, 111, 114, 107, 0, 123, 56, 55, 49, 57, 49, 99, 97, 48, 45, 48, 102, 99, 57, 45, + 49, 49, 100, 52, 45, 56, 52, 57, 97, 45, 48, 48, 48, 53, 48, 50, 98, 53, 50, 49, 50, + 50, 125, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 3, 1, 81, 62, 0, 0, 175, 149, 170, 0, 0, 0, 0, + 0, 93, 12, 238, 0, 16, 0, 24, 0, 116, 131, 160, 0, 0, 0, 0, 128, 255, 15, 1, 0, 68, 54, + 0, 0, 67, 1, 33, 4, 0, 0, 1, 0, 4, 0, 3, 1, 34, 62, 0, 0, 175, 149, 170, 0, 0, 0, 0, 0, + 132, 224, 240, 0, 16, 0, 24, 0, 116, 131, 160, 0, 0, 0, 0, 128, 254, 15, 1, 0, 23, 51, + 0, 0, 67, 1, 33, 4, 0, 0, 1, 0, 4, 0, 5, 2, 208, 150, 65, 6, 175, 149, 170, 0, 0, 0, 0, + 0, 209, 145, 99, 1, 16, 0, 16, 0, 116, 131, 160, 0, 0, 0, 0, 128, 252, 218, 62, 6, 1, + 0, 0, 0, 4, 0, 4, 2, 64, 153, 65, 6, 175, 149, 170, 0, 0, 0, 0, 0, 240, 9, 131, 253, + 22, 0, 8, 0, 140, 94, 64, 6, 1, 0, 0, 0, 4, 0, 4, 2, 96, 153, 65, 6, 175, 149, 170, 0, + 0, 0, 0, 0, 167, 26, 131, 253, 22, 0, 8, 0, 216, 115, 64, 6, 1, 0, 0, 0, 0, 0, + ]; + let (_, results) = FirehosePreamble::parse_firehose_preamble(&data).unwrap(); + assert_eq!(results.private_data_virtual_offset, 4094); + assert_eq!(results.first_number_proc_id, 1189179); + assert_eq!(results.second_number_proc_id, 2685254); + assert_eq!(results.base_continous_time, 2686068189033091); + assert_eq!(results.public_data_size, 664); + assert_eq!(results.public_data.len(), 10); + assert_eq!(results.collapsed, 1); + } + + #[test] + fn test_get_firehose_items() { + let test_data = [ + 66, 4, 0, 0, 73, 0, 91, 97, 112, 112, 60, 97, 112, 112, 108, 105, 99, 97, 116, 105, + 111, 110, 46, 99, 111, 109, 46, 111, 98, 106, 101, 99, 116, 105, 118, 101, 45, 115, + 101, 101, 46, 108, 117, 108, 117, 46, 97, 112, 112, 46, 50, 57, 51, 53, 48, 52, 52, 52, + 46, 50, 57, 51, 53, 48, 52, 53, 48, 40, 53, 48, 49, 41, 62, 58, 54, 52, 49, 93, 0, + ]; + let (_, results) = FirehosePreamble::get_firehose_items(&test_data).unwrap(); + assert_eq!(results.item_type, 66); + assert_eq!(results.item_size, 4); + assert_eq!(results.offset, 0); + assert_eq!(results.message_string_size, 73); + } + + #[test] + fn test_parse_item_number() { + let test_data = [1, 0, 0, 0]; + let test_size = 4; + let (_, results) = FirehosePreamble::parse_item_number(&test_data, test_size).unwrap(); + assert_eq!(results, 1); + } + + #[test] + fn test_parse_item_string() { + let test_data = [55, 57, 54, 46, 49, 48, 48, 0]; + let test_item = 34; + let test_size = 8; + let (_, results) = + FirehosePreamble::parse_item_string(&test_data, &test_item, test_size).unwrap(); + assert_eq!(results, "796.100"); + } + + #[test] + fn test_parse_firehose_has_private_strings_big_sur() { + let test_data = [ + 1, 96, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 0, 0, 0, 143, 0, 0, 0, 0, 0, 0, 0, 100, 1, 0, + 0, 0, 1, 0, 0, 56, 0, 165, 15, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 1, 16, 63, + 0, 0, 189, 3, 0, 0, 0, 0, 0, 0, 143, 31, 133, 28, 1, 0, 16, 0, 165, 15, 91, 0, 120, 58, + 0, 0, 67, 1, 33, 4, 0, 0, 91, 0, 82, 101, 99, 114, 101, 97, 116, 105, 110, 103, 32, 83, + 121, 115, 116, 101, 109, 46, 107, 101, 121, 99, 104, 97, 105, 110, 32, 98, 101, 99, 97, + 117, 115, 101, 32, 105, 116, 32, 99, 97, 110, 110, 111, 116, 32, 117, 110, 108, 111, + 99, 107, 59, 32, 115, 101, 101, 32, 47, 117, 115, 114, 47, 108, 105, 98, 101, 120, 101, + 99, 47, 115, 101, 99, 117, 114, 105, 116, 121, 45, 99, 104, 101, 99, 107, 115, 121, + 115, 116, 101, 109, 0, + ]; + let (_, firehose) = FirehosePreamble::parse_firehose_preamble(&test_data).unwrap(); + assert_eq!(firehose.chunk_tag, 0x6001); + assert_eq!(firehose.chunk_sub_tag, 0); + assert_eq!(firehose.chunk_data_size, 163); + assert_eq!(firehose.first_number_proc_id, 143); + assert_eq!(firehose.second_number_proc_id, 356); + assert_eq!(firehose.collapsed, 1); + assert_eq!(firehose.ttl, 0); + assert_eq!(firehose.unknown, [0, 0]); + assert_eq!(firehose.public_data_size, 56); + assert_eq!(firehose.private_data_virtual_offset, 4005); + assert_eq!(firehose.unkonwn2, 0); + assert_eq!(firehose.unknown3, 512); + assert_eq!(firehose.base_continous_time, 0); + + assert_eq!(firehose.public_data.len(), 1); + assert_eq!(firehose.public_data[0].unknown_log_activity_type, 4); + assert_eq!(firehose.public_data[0].unknown_log_type, 0); + assert_eq!(firehose.public_data[0].flags, 258); + assert_eq!(firehose.public_data[0].format_string_location, 16144); + assert_eq!(firehose.public_data[0].thread_id, 957); + assert_eq!(firehose.public_data[0].continous_time_delta_upper, 1); + assert_eq!(firehose.public_data[0].continous_time_delta, 478486415); + assert_eq!(firehose.public_data[0].data_size, 16); + + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .unknown_activity_id, + 0 + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .unknown_sentinal, + 0 + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .private_strings_offset, + 4005 + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .private_strings_size, + 91 + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .unknown_message_string_ref, + 0 + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .subsystem_value, + 0 + ); + assert_eq!(firehose.public_data[0].firehose_non_activity.ttl_value, 0); + assert_eq!( + firehose.public_data[0].firehose_non_activity.data_ref_value, + 0 + ); + assert_eq!( + firehose.public_data[0].firehose_non_activity.unknown_pc_id, + 14968 + ); + + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .main_exe, + true + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .shared_cache, + false + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .has_large_offset, + 0 + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .large_shared_cache, + 0 + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .absolute, + false + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .uuid_relative, + String::new() + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .main_plugin, + false + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .pc_style, + false + ); + assert_eq!( + firehose.public_data[0] + .firehose_non_activity + .firehose_formatters + .main_exe_alt_index, + 0 + ); + } + + #[test] + fn test_get_backtrace() { + let test_data = [ + 1, 0, 18, 7, 19, 0, 73, 103, 10, 236, 77, 93, 51, 131, 144, 108, 35, 245, 104, 53, 31, + 203, 169, 187, 202, 141, 55, 86, 63, 143, 187, 183, 127, 59, 151, 143, 42, 81, 94, 53, + 105, 87, 179, 55, 63, 107, 172, 169, 193, 26, 210, 26, 101, 9, 10, 32, 146, 176, 222, + 171, 50, 147, 154, 138, 220, 226, 237, 32, 38, 224, 186, 122, 214, 20, 242, 194, 62, + 137, 144, 67, 67, 221, 84, 138, 229, 177, 106, 194, 74, 58, 138, 149, 63, 163, 164, 42, + 215, 219, 179, 150, 30, 162, 252, 36, 0, 196, 33, 0, 55, 62, 183, 136, 73, 210, 38, 64, + 67, 155, 91, 36, 0, 0, 171, 102, 0, 0, 118, 1, 3, 0, 237, 0, 3, 0, 6, 56, 0, 0, 140, + 73, 0, 0, 219, 0, 3, 0, 196, 162, 33, 0, 205, 110, 38, 0, 189, 35, 0, 0, 215, 42, 0, 0, + 91, 40, 0, 0, 181, 56, 0, 0, 35, 38, 0, 0, 6, 56, 0, 0, 118, 41, 1, 0, 112, 47, 1, 0, + 23, 52, 0, 0, 47, 36, 0, 0, 6, 6, 5, 5, 4, 4, 5, 3, 3, 3, 2, 2, 1, 4, 4, 4, 4, 0, 0, 0, + 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 112, 114, 105, 118, 97, 116, 101, 46, + 115, 117, 103, 103, 101, 115, 116, 105, 111, 110, 115, 46, 101, 118, 101, 110, 116, + 115, 0, + ]; + let (_, results) = FirehosePreamble::get_backtrace_data(&test_data).unwrap(); + assert_eq!(results.len(), 19); + assert_eq!( + results, + vec![ + "\"FC2400C42100373EB78849D22640439B\" +0x9307", + "\"FC2400C42100373EB78849D22640439B\" +0x26283", + "\"6AC24A3A8A953FA3A42AD7DBB3961EA2\" +0x196982", + "\"6AC24A3A8A953FA3A42AD7DBB3961EA2\" +0x196845", + "\"BA7AD614F2C23E89904343DD548AE5B1\" +0x14342", + "\"BA7AD614F2C23E89904343DD548AE5B1\" +0x18828", + "\"6AC24A3A8A953FA3A42AD7DBB3961EA2\" +0x196827", + "\"A2092B0DEAB32939A8ADCE2ED2026E0\" +0x2204356", + "\"A2092B0DEAB32939A8ADCE2ED2026E0\" +0x2518733", + "\"A2092B0DEAB32939A8ADCE2ED2026E0\" +0x9149", + "\"5E356957B3373F6BACA9C11AD21A6509\" +0x10967", + "\"5E356957B3373F6BACA9C11AD21A6509\" +0x10331", + "\"A9BBCA8D37563F8FBBB77F3B978F2A51\" +0x14517", + "\"BA7AD614F2C23E89904343DD548AE5B1\" +0x9763", + "\"BA7AD614F2C23E89904343DD548AE5B1\" +0x14342", + "\"BA7AD614F2C23E89904343DD548AE5B1\" +0x76150", + "\"BA7AD614F2C23E89904343DD548AE5B1\" +0x77680", + "\"49670AEC4D5D3383906C23F568351FCB\" +0x13335", + "\"49670AEC4D5D3383906C23F568351FCB\" +0x9263" + ] + ); + } + + #[test] + fn test_collect_items() { + let test_data = [65, 4, 0, 0, 0, 0]; + let firehose_number_items = 1; + let firehose_flags = 513; + let (_, results) = + FirehosePreamble::collect_items(&test_data, &firehose_number_items, &firehose_flags) + .unwrap(); + assert_eq!(results.item_info[0].message_strings, ""); + assert_eq!(results.item_info[0].item_type, 65); + assert_eq!(results.backtrace_strings.len(), 0); + } + + #[test] + fn test_parse_firehose_preamble_private_public_values() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Chunkset Tests/private_public_data.raw"); + + let mut open = File::open(test_path).unwrap(); + + let mut buffer = Vec::new(); + open.read_to_end(&mut buffer).unwrap(); + + let (_, results) = FirehosePreamble::parse_firehose_preamble(&buffer).unwrap(); + + assert_eq!(results.public_data.len(), 51); + + let mut private_public_string_count = 0; + for entries in results.public_data { + for firehose_entries in entries.message.item_info { + if firehose_entries.message_strings == "EMAIL_PRIVATE_LINK_MENU_TITLE" + || firehose_entries.message_strings == "Send private link by email …" + { + private_public_string_count += 1; + } + } + } + // EMAIL_PRIVATE_LINK_MENU_TITLE is a private string + // Send private link by email … is a public string + // both in same log entry + assert_eq!(private_public_string_count, 2); + } + + #[test] + #[should_panic(expected = "Eof")] + fn test_collect_items_bad_length() { + let test_data = [65, 4]; + let firehose_number_items = 1; + let firehose_flags = 513; + let (_, _) = + FirehosePreamble::collect_items(&test_data, &firehose_number_items, &firehose_flags) + .unwrap(); + } + + #[test] + fn test_parse_private_data() { + let test_data = [ + 60, 83, 90, 69, 120, 116, 114, 97, 99, 116, 111, 114, 60, 48, 120, 49, 53, 55, 56, 48, + 101, 101, 54, 48, 62, 32, 112, 114, 101, 112, 97, 114, 101, 100, 58, 89, 32, 118, 97, + 108, 105, 100, 58, 89, 32, 112, 97, 116, 104, 69, 110, 100, 105, 110, 103, 58, 99, 111, + 109, 46, 97, 112, 112, 108, 101, 46, 110, 115, 117, 114, 108, 115, 101, 115, 115, 105, + 111, 110, 100, 47, 67, 70, 78, 101, 116, 119, 111, 114, 107, 68, 111, 119, 110, 108, + 111, 97, 100, 95, 121, 87, 104, 53, 107, 56, 46, 116, 109, 112, 32, 101, 114, 114, 111, + 114, 58, 40, 110, 117, 108, 108, 41, 62, 58, 32, 83, 117, 112, 112, 108, 121, 32, 98, + 121, 116, 101, 115, 32, 119, 105, 116, 104, 32, 108, 101, 110, 103, 116, 104, 32, 54, + 53, 53, 51, 54, 32, 98, 101, 103, 97, 110, 0, + ]; + let mut results: FirehoseItemData = FirehoseItemData { + item_info: Vec::new(), + backtrace_strings: Vec::new(), + }; + let firehose_item: FirehoseItemInfo = FirehoseItemInfo { + message_strings: String::new(), + item_type: 33, + item_size: 161, + }; + results.item_info.push(firehose_item); + let (_, _) = FirehosePreamble::parse_private_data(&test_data, &mut results).unwrap(); + + assert_eq!(results.item_info[0].message_strings, " prepared:Y valid:Y pathEnding:com.apple.nsurlsessiond/CFNetworkDownload_yWh5k8.tmp error:(null)>: Supply bytes with length 65536 began") + } + + #[test] + fn test_parse_private_number_data() { + let test_data = [60, 83, 90, 69, 120, 116, 114, 97]; + let mut results: FirehoseItemData = FirehoseItemData { + item_info: Vec::new(), + backtrace_strings: Vec::new(), + }; + let firehose_item: FirehoseItemInfo = FirehoseItemInfo { + message_strings: String::new(), + item_type: 1, + item_size: 8, + }; + results.item_info.push(firehose_item); + let (_, _) = FirehosePreamble::parse_private_data(&test_data, &mut results).unwrap(); + + assert_eq!(results.item_info[0].message_strings, "7021802828932469564") + } + + #[test] + fn test_collect_items_unknown_item() { + let test_data = [ + 99, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, + ]; + let firehose_number_items = 1; + let firehose_flags = 513; + let (_, results) = + FirehosePreamble::collect_items(&test_data, &firehose_number_items, &firehose_flags) + .unwrap(); + assert_eq!(results.item_info[0].message_strings, ""); + assert_eq!(results.item_info[0].item_type, 99); + assert_eq!(results.backtrace_strings.len(), 0); + } + + #[test] + fn test_firehose_header_continous_time_zero() { + let test_data = [ + 1, 96, 0, 0, 0, 0, 0, 0, 8, 16, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, + 0, 0, 0, 0, 248, 15, 0, 16, 0, 16, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 2, 96, 181, + 7, 0, 110, 2, 0, 0, 0, 0, 0, 0, 145, 82, 253, 56, 2, 0, 22, 0, 192, 190, 4, 0, 1, 0, 2, + 1, 34, 4, 0, 0, 8, 0, 52, 56, 51, 46, 55, 48, 48, 0, 0, 0, 4, 0, 2, 2, 96, 160, 7, 0, + 149, 2, 0, 0, 0, 0, 0, 0, 11, 10, 22, 65, 2, 0, 63, 0, 150, 69, 4, 0, 2, 0, 2, 4, 32, + 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 66, 4, 2, 0, 18, 0, 32, 4, 20, 0, 11, 0, 0, 0, 47, + 65, 99, 116, 105, 118, 101, 32, 68, 105, 114, 101, 99, 116, 111, 114, 121, 0, 32, 97, + 115, 32, 104, 105, 100, 100, 101, 110, 0, 0, 4, 0, 2, 2, 96, 160, 7, 0, 149, 2, 0, 0, + 0, 0, 0, 0, 95, 252, 71, 65, 2, 0, 52, 0, 150, 69, 4, 0, 2, 0, 2, 4, 32, 4, 0, 0, 1, 0, + 32, 4, 1, 0, 1, 0, 66, 4, 2, 0, 7, 0, 32, 4, 9, 0, 11, 0, 0, 0, 47, 76, 111, 99, 97, + 108, 0, 32, 97, 115, 32, 104, 105, 100, 100, 101, 110, 0, 0, 0, 0, 0, 4, 0, 2, 2, 224, + 164, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 102, 107, 93, 65, 2, 0, 79, 0, 224, 244, 3, 0, 1, + 0, 2, 2, 66, 4, 0, 0, 8, 0, 34, 4, 8, 0, 51, 0, 47, 83, 101, 97, 114, 99, 104, 0, 47, + 76, 105, 98, 114, 97, 114, 121, 47, 80, 114, 101, 102, 101, 114, 101, 110, 99, 101, + 115, 47, 79, 112, 101, 110, 68, 105, 114, 101, 99, 116, 111, 114, 121, 47, 67, 111, + 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 115, 47, 0, 0, 4, 0, 2, 2, 112, + 166, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 108, 129, 94, 65, 2, 0, 92, 0, 209, 253, 3, 0, 1, + 0, 2, 2, 66, 4, 0, 0, 8, 0, 66, 4, 8, 0, 64, 0, 47, 83, 101, 97, 114, 99, 104, 0, 47, + 76, 105, 98, 114, 97, 114, 121, 47, 80, 114, 101, 102, 101, 114, 101, 110, 99, 101, + 115, 47, 79, 112, 101, 110, 68, 105, 114, 101, 99, 116, 111, 114, 121, 47, 67, 111, + 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 115, 47, 47, 83, 101, 97, 114, + 99, 104, 46, 112, 108, 105, 115, 116, 0, 0, 0, 0, 0, 4, 0, 2, 2, 96, 160, 7, 0, 149, 2, + 0, 0, 0, 0, 0, 0, 198, 144, 94, 65, 2, 0, 43, 0, 150, 69, 4, 0, 2, 0, 2, 4, 32, 4, 0, + 0, 1, 0, 32, 4, 1, 0, 1, 0, 66, 4, 2, 0, 8, 0, 32, 4, 10, 0, 1, 0, 0, 0, 47, 83, 101, + 97, 114, 99, 104, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 2, 96, 160, 7, 0, 149, 2, 0, 0, 0, 0, + 0, 0, 218, 0, 106, 65, 2, 0, 53, 0, 150, 69, 4, 0, 2, 0, 2, 4, 32, 4, 0, 0, 1, 0, 32, + 4, 1, 0, 1, 0, 66, 4, 2, 0, 8, 0, 32, 4, 10, 0, 11, 0, 0, 0, 47, 76, 68, 65, 80, 118, + 51, 0, 32, 97, 115, 32, 104, 105, 100, 100, 101, 110, 0, 0, 0, 0, 4, 0, 2, 2, 96, 160, + 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 176, 255, 116, 65, 2, 0, 56, 0, 150, 69, 4, 0, 2, 0, 2, + 4, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 66, 4, 2, 0, 11, 0, 32, 4, 13, 0, 11, 0, 0, 0, + 47, 67, 111, 110, 102, 105, 103, 117, 114, 101, 0, 32, 97, 115, 32, 104, 105, 100, 100, + 101, 110, 0, 4, 0, 2, 2, 224, 164, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 63, 138, 136, 65, 2, + 0, 81, 0, 224, 244, 3, 0, 1, 0, 2, 2, 66, 4, 0, 0, 10, 0, 34, 4, 10, 0, 51, 0, 47, 67, + 111, 110, 116, 97, 99, 116, 115, 0, 47, 76, 105, 98, 114, 97, 114, 121, 47, 80, 114, + 101, 102, 101, 114, 101, 110, 99, 101, 115, 47, 79, 112, 101, 110, 68, 105, 114, 101, + 99, 116, 111, 114, 121, 47, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, + 110, 115, 47, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 2, 112, 166, 7, 0, 149, 2, 0, 0, 0, 0, + 0, 0, 100, 26, 138, 65, 2, 0, 96, 0, 209, 253, 3, 0, 1, 0, 2, 2, 66, 4, 0, 0, 10, 0, + 66, 4, 10, 0, 66, 0, 47, 67, 111, 110, 116, 97, 99, 116, 115, 0, 47, 76, 105, 98, 114, + 97, 114, 121, 47, 80, 114, 101, 102, 101, 114, 101, 110, 99, 101, 115, 47, 79, 112, + 101, 110, 68, 105, 114, 101, 99, 116, 111, 114, 121, 47, 67, 111, 110, 102, 105, 103, + 117, 114, 97, 116, 105, 111, 110, 115, 47, 47, 67, 111, 110, 116, 97, 99, 116, 115, 46, + 112, 108, 105, 115, 116, 0, 4, 0, 2, 2, 96, 160, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 127, + 41, 138, 65, 2, 0, 45, 0, 150, 69, 4, 0, 2, 0, 2, 4, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, + 0, 66, 4, 2, 0, 10, 0, 32, 4, 12, 0, 1, 0, 0, 0, 47, 67, 111, 110, 116, 97, 99, 116, + 115, 0, 0, 0, 0, 0, 4, 0, 2, 2, 32, 128, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 105, 23, 104, + 67, 2, 0, 8, 0, 86, 122, 2, 0, 2, 0, 0, 0, 4, 0, 2, 2, 96, 160, 7, 0, 198, 2, 0, 0, 0, + 0, 0, 0, 4, 105, 122, 67, 2, 0, 53, 0, 150, 69, 4, 0, 2, 0, 2, 4, 32, 4, 0, 0, 1, 0, + 32, 4, 1, 0, 4, 0, 66, 4, 5, 0, 15, 0, 32, 4, 20, 0, 1, 0, 0, 115, 117, 98, 0, 47, 76, + 111, 99, 97, 108, 47, 68, 101, 102, 97, 117, 108, 116, 0, 0, 0, 0, 0, 2, 1, 2, 0, 112, + 167, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 33, 251, 126, 67, 2, 0, 12, 0, 80, 0, 0, 0, 0, 0, + 0, 128, 148, 3, 4, 0, 0, 0, 0, 0, 2, 1, 2, 0, 112, 167, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, + 189, 237, 146, 67, 2, 0, 12, 0, 81, 0, 0, 0, 0, 0, 0, 128, 148, 3, 4, 0, 0, 0, 0, 0, 4, + 0, 3, 2, 208, 167, 7, 0, 201, 2, 0, 0, 0, 0, 0, 0, 210, 210, 156, 67, 2, 0, 29, 0, 80, + 0, 0, 0, 0, 0, 0, 128, 113, 150, 4, 0, 2, 0, 2, 1, 66, 4, 0, 0, 7, 0, 47, 76, 111, 99, + 97, 108, 0, 0, 0, 0, 4, 0, 3, 2, 208, 167, 7, 0, 152, 2, 0, 0, 0, 0, 0, 0, 133, 143, + 163, 67, 2, 0, 37, 0, 81, 0, 0, 0, 0, 0, 0, 128, 113, 150, 4, 0, 2, 0, 2, 1, 66, 4, 0, + 0, 15, 0, 47, 76, 111, 99, 97, 108, 47, 68, 101, 102, 97, 117, 108, 116, 0, 0, 0, 0, 2, + 1, 2, 0, 144, 129, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 63, 2, 174, 67, 2, 0, 12, 0, 82, 0, + 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 2, 0, 112, 167, 7, 0, 149, 2, 0, + 0, 0, 0, 0, 0, 207, 141, 30, 68, 2, 0, 12, 0, 83, 0, 0, 0, 0, 0, 0, 128, 148, 3, 4, 0, + 0, 0, 0, 0, 4, 0, 3, 2, 208, 167, 7, 0, 201, 2, 0, 0, 0, 0, 0, 0, 135, 40, 46, 68, 2, + 0, 30, 0, 83, 0, 0, 0, 0, 0, 0, 128, 113, 150, 4, 0, 2, 0, 2, 1, 66, 4, 0, 0, 8, 0, 47, + 83, 101, 97, 114, 99, 104, 0, 0, 0, 2, 1, 2, 0, 144, 129, 7, 0, 149, 2, 0, 0, 0, 0, 0, + 0, 121, 211, 50, 68, 2, 0, 12, 0, 84, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, + 4, 0, 2, 2, 128, 182, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 183, 118, 74, 68, 2, 0, 8, 0, + 120, 201, 4, 0, 1, 0, 0, 0, 2, 1, 2, 0, 240, 188, 7, 0, 211, 2, 0, 0, 0, 0, 0, 0, 237, + 96, 77, 68, 2, 0, 12, 0, 85, 0, 0, 0, 0, 0, 0, 128, 14, 22, 5, 0, 0, 0, 0, 0, 2, 1, 19, + 0, 144, 129, 7, 0, 211, 2, 0, 0, 0, 0, 0, 0, 165, 204, 81, 68, 2, 0, 28, 0, 85, 0, 0, + 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, + 0, 0, 0, 2, 1, 19, 2, 176, 129, 7, 0, 176, 2, 0, 0, 0, 0, 0, 0, 43, 85, 223, 68, 2, 0, + 36, 0, 86, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 128, + 87, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 2, 0, 240, 188, 7, 0, 211, + 2, 0, 0, 0, 0, 0, 0, 238, 110, 2, 69, 2, 0, 12, 0, 88, 0, 0, 0, 0, 0, 0, 128, 14, 22, + 5, 0, 0, 0, 0, 0, 2, 1, 19, 0, 144, 129, 7, 0, 211, 2, 0, 0, 0, 0, 0, 0, 22, 27, 3, 69, + 2, 0, 28, 0, 88, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, + 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 176, 129, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, + 118, 47, 17, 69, 2, 0, 36, 0, 89, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 89, + 0, 0, 0, 0, 0, 0, 128, 90, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 4, 0, 10, + 2, 192, 149, 3, 0, 198, 2, 0, 0, 0, 0, 0, 0, 232, 5, 76, 69, 2, 0, 24, 0, 119, 48, 2, + 0, 91, 240, 239, 78, 191, 142, 58, 183, 183, 206, 80, 92, 202, 151, 165, 240, 1, 0, 0, + 0, 4, 0, 10, 2, 0, 150, 3, 0, 198, 2, 0, 0, 0, 0, 0, 0, 123, 56, 76, 69, 2, 0, 48, 0, + 107, 49, 2, 0, 91, 240, 239, 78, 191, 142, 58, 183, 183, 206, 80, 92, 202, 151, 165, + 240, 1, 0, 0, 4, 0, 4, 100, 0, 0, 0, 0, 4, 250, 0, 0, 0, 0, 4, 100, 0, 0, 0, 0, 4, 244, + 1, 0, 0, 2, 1, 19, 0, 144, 129, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 197, 70, 91, 69, 2, 0, + 28, 0, 48, 0, 0, 0, 0, 0, 0, 128, 87, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 128, + 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 144, 129, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 83, + 57, 115, 69, 2, 0, 36, 0, 48, 0, 0, 0, 0, 0, 0, 128, 87, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, + 0, 0, 0, 0, 128, 92, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, + 176, 129, 7, 0, 218, 2, 0, 0, 0, 0, 0, 0, 85, 38, 119, 69, 2, 0, 36, 0, 92, 0, 0, 0, 0, + 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 128, 93, 0, 0, 0, 0, 0, 0, + 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 27, 0, 128, 124, 3, 0, 202, 2, 0, 0, 0, 0, 0, 0, + 180, 174, 82, 75, 2, 0, 44, 0, 65, 0, 0, 0, 0, 0, 0, 128, 52, 0, 0, 0, 0, 0, 0, 0, 94, + 0, 0, 0, 0, 0, 0, 128, 20, 60, 1, 0, 91, 240, 239, 78, 191, 142, 58, 183, 183, 206, 80, + 92, 202, 151, 165, 240, 0, 0, 0, 0, 4, 0, 3, 2, 160, 131, 7, 0, 223, 2, 0, 0, 0, 0, 0, + 0, 202, 23, 87, 75, 2, 0, 37, 0, 65, 0, 0, 0, 0, 0, 0, 128, 195, 148, 2, 0, 2, 0, 2, 2, + 66, 4, 0, 0, 9, 0, 0, 4, 2, 0, 0, 0, 103, 101, 116, 112, 119, 117, 105, 100, 0, 0, 0, + 0, 4, 0, 3, 2, 160, 131, 7, 0, 202, 2, 0, 0, 0, 0, 0, 0, 94, 173, 88, 75, 2, 0, 37, 0, + 177, 0, 0, 0, 0, 0, 0, 128, 195, 148, 2, 0, 2, 0, 2, 2, 66, 4, 0, 0, 9, 0, 0, 4, 2, 0, + 0, 0, 103, 101, 116, 112, 119, 117, 105, 100, 0, 0, 0, 0, 2, 1, 27, 0, 128, 124, 3, 0, + 201, 2, 0, 0, 0, 0, 0, 0, 53, 143, 107, 75, 2, 0, 44, 0, 48, 0, 0, 0, 0, 0, 0, 128, 87, + 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 128, 20, 60, 1, 0, 91, 240, 239, 78, 191, + 142, 58, 183, 183, 206, 80, 92, 202, 151, 165, 240, 0, 0, 0, 0, 4, 0, 3, 2, 160, 131, + 7, 0, 218, 2, 0, 0, 0, 0, 0, 0, 3, 55, 153, 75, 2, 0, 37, 0, 48, 0, 0, 0, 0, 0, 0, 128, + 195, 148, 2, 0, 2, 0, 2, 2, 66, 4, 0, 0, 9, 0, 0, 4, 2, 0, 0, 0, 103, 101, 116, 112, + 119, 117, 105, 100, 0, 0, 0, 0, 2, 1, 19, 2, 144, 129, 7, 0, 218, 2, 0, 0, 0, 0, 0, 0, + 198, 84, 136, 77, 2, 0, 36, 0, 182, 0, 0, 0, 0, 0, 0, 128, 65, 0, 0, 0, 0, 0, 0, 0, + 182, 0, 0, 0, 0, 0, 0, 128, 208, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, + 1, 19, 2, 176, 129, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 11, 143, 139, 77, 2, 0, 36, 0, 208, + 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, 128, 209, 0, 0, + 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 0, 144, 129, 7, 0, 202, 2, 0, 0, + 0, 0, 0, 0, 57, 51, 178, 77, 2, 0, 28, 0, 182, 0, 0, 0, 0, 0, 0, 128, 65, 0, 0, 0, 0, + 0, 0, 0, 210, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 144, 129, + 7, 0, 218, 2, 0, 0, 0, 0, 0, 0, 117, 196, 196, 77, 2, 0, 36, 0, 182, 0, 0, 0, 0, 0, 0, + 128, 65, 0, 0, 0, 0, 0, 0, 0, 182, 0, 0, 0, 0, 0, 0, 128, 211, 0, 0, 0, 0, 0, 0, 128, + 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 0, 144, 129, 7, 0, 218, 2, 0, 0, 0, 0, 0, 0, 252, + 223, 207, 77, 2, 0, 28, 0, 182, 0, 0, 0, 0, 0, 0, 128, 65, 0, 0, 0, 0, 0, 0, 0, 212, 0, + 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 176, 129, 7, 0, 7, 3, 0, 0, + 0, 0, 0, 0, 165, 245, 209, 77, 2, 0, 36, 0, 212, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, + 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 128, 213, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, + 0, 0, 2, 1, 19, 2, 144, 129, 7, 0, 6, 3, 0, 0, 0, 0, 0, 0, 94, 88, 40, 78, 2, 0, 36, 0, + 183, 0, 0, 0, 0, 0, 0, 128, 65, 0, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 128, 214, + 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 176, 129, 7, 0, 149, 2, + 0, 0, 0, 0, 0, 0, 251, 88, 43, 78, 2, 0, 36, 0, 214, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, + 0, 0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 128, 215, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, + 0, 0, 0, 0, 2, 1, 2, 0, 232, 129, 7, 0, 198, 2, 0, 0, 0, 0, 0, 0, 190, 47, 49, 78, 2, + 0, 12, 0, 216, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 2, 0, 232, 129, + 7, 0, 198, 2, 0, 0, 0, 0, 0, 0, 153, 1, 68, 78, 2, 0, 12, 0, 217, 0, 0, 0, 0, 0, 0, + 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 144, 129, 7, 0, 218, 2, 0, 0, 0, 0, 0, 0, + 202, 100, 90, 78, 2, 0, 36, 0, 216, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, + 216, 0, 0, 0, 0, 0, 0, 128, 218, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, + 1, 19, 2, 176, 129, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 122, 148, 92, 78, 2, 0, 36, 0, 218, + 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 128, 219, 0, 0, + 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 27, 0, 128, 124, 3, 0, 202, 2, 0, 0, + 0, 0, 0, 0, 126, 98, 93, 78, 2, 0, 44, 0, 183, 0, 0, 0, 0, 0, 0, 128, 65, 0, 0, 0, 0, + 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 128, 20, 60, 1, 0, 91, 240, 239, 78, 191, 142, 58, 183, + 183, 206, 80, 92, 202, 151, 165, 240, 0, 0, 0, 0, 2, 1, 19, 2, 144, 129, 7, 0, 202, 2, + 0, 0, 0, 0, 0, 0, 177, 30, 94, 78, 2, 0, 36, 0, 220, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, + 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 128, 221, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, + 0, 0, 0, 0, 2, 1, 19, 2, 176, 129, 7, 0, 201, 2, 0, 0, 0, 0, 0, 0, 121, 56, 97, 78, 2, + 0, 36, 0, 221, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 0, 0, 0, + 128, 222, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 2, 0, 232, 129, 7, + 0, 198, 2, 0, 0, 0, 0, 0, 0, 151, 19, 173, 78, 2, 0, 12, 0, 223, 0, 0, 0, 0, 0, 0, 128, + 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 144, 129, 7, 0, 7, 3, 0, 0, 0, 0, 0, 0, 56, + 185, 189, 78, 2, 0, 36, 0, 217, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 217, 0, + 0, 0, 0, 0, 0, 128, 224, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, + 176, 129, 7, 0, 6, 3, 0, 0, 0, 0, 0, 0, 214, 177, 192, 78, 2, 0, 36, 0, 224, 0, 0, 0, + 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 128, 225, 0, 0, 0, 0, 0, + 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 2, 0, 232, 129, 7, 0, 198, 2, 0, 0, 0, 0, 0, + 0, 67, 212, 2, 79, 2, 0, 12, 0, 226, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, + 2, 1, 19, 2, 144, 129, 7, 0, 23, 3, 0, 0, 0, 0, 0, 0, 130, 167, 41, 79, 2, 0, 36, 0, + 223, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, 0, 0, 0, 0, 128, 227, + 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 176, 129, 7, 0, 218, 2, + 0, 0, 0, 0, 0, 0, 6, 193, 46, 79, 2, 0, 36, 0, 227, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, + 0, 0, 0, 0, 227, 0, 0, 0, 0, 0, 0, 128, 228, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, + 0, 0, 0, 2, 1, 2, 0, 232, 129, 7, 0, 198, 2, 0, 0, 0, 0, 0, 0, 163, 140, 70, 79, 2, 0, + 12, 0, 229, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 2, 0, 232, 129, 7, + 0, 198, 2, 0, 0, 0, 0, 0, 0, 32, 170, 237, 79, 2, 0, 12, 0, 230, 0, 0, 0, 0, 0, 0, 128, + 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 144, 129, 7, 0, 149, 2, 0, 0, 0, 0, 0, 0, 79, + 141, 239, 79, 2, 0, 36, 0, 226, 0, 0, 0, 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 226, 0, + 0, 0, 0, 0, 0, 128, 231, 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, + 176, 129, 7, 0, 202, 2, 0, 0, 0, 0, 0, 0, 185, 201, 243, 79, 2, 0, 36, 0, 231, 0, 0, 0, + 0, 0, 0, 128, 59, 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 128, 232, 0, 0, 0, 0, 0, + 0, 128, 122, 137, 2, 0, 0, 0, 0, 0, 2, 1, 2, 0, 232, 129, 7, 0, 198, 2, 0, 0, 0, 0, 0, + 0, 30, 120, 183, 81, 2, 0, 12, 0, 233, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, 0, 0, 0, + 0, 2, 1, 19, 2, 144, 129, 7, 0, 223, 2, 0, 0, 0, 0, 0, 0, 154, 0, 6, 83, 2, 0, 36, 0, + 150, 0, 0, 0, 0, 0, 0, 128, 60, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 128, 234, + 0, 0, 0, 0, 0, 0, 128, 43, 137, 2, 0, 0, 0, 0, 0, 2, 1, 19, 2, 176, 129, 7, 0, 223, 2, + 0, 0, 0, 0, 0, 0, 134, 94, 14, 83, 2, 0, 36, 0, 150, 0, 0, 0, 0, 0, 0, 128, 60, 0, 0, + 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 128, 235, 0, 0, 0, 0, 0, 0, 128, 122, 137, 2, 0, + 0, 0, 0, 0, + ]; + + let (mut data, firehose) = FirehosePreamble::parse_firehose_preamble(&test_data).unwrap(); + assert_eq!(firehose.chunk_tag, 0x6001); + assert_eq!(firehose.chunk_sub_tag, 0); + assert_eq!(firehose.chunk_data_size, 4104); + assert_eq!(firehose.first_number_proc_id, 59); + assert_eq!(firehose.second_number_proc_id, 60); + assert_eq!(firehose.collapsed, 0); + assert_eq!(firehose.ttl, 0); + assert_eq!(firehose.unknown, [0, 0]); + assert_eq!(firehose.public_data_size, 4088); + assert_eq!(firehose.private_data_virtual_offset, 4096); + assert_eq!(firehose.unkonwn2, 4096); + assert_eq!(firehose.unknown3, 768); + assert_eq!(firehose.base_continous_time, 0); + + let mut firehouse_result_count = firehose.public_data.len(); + while data.len() != 0 { + let (test_data, firehose) = FirehosePreamble::parse_firehose_preamble(&data).unwrap(); + data = test_data; + firehouse_result_count += firehose.public_data.len(); + } + assert_eq!(firehouse_result_count, 66) + } +} diff --git a/src/chunks/firehose/flags.rs b/src/chunks/firehose/flags.rs new file mode 100644 index 0000000..5e83a26 --- /dev/null +++ b/src/chunks/firehose/flags.rs @@ -0,0 +1,209 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::{debug, error}; +use nom::bytes::complete::take; +use nom::number::complete::{be_u128, le_u16}; +use nom::Needed; +use std::mem::size_of; + +#[derive(Debug, Clone)] +pub struct FirehoseFormatters { + pub main_exe: bool, + pub shared_cache: bool, + pub has_large_offset: u16, + pub large_shared_cache: u16, + pub absolute: bool, + pub uuid_relative: String, + pub main_plugin: bool, // Not seen yet + pub pc_style: bool, // Not seen yet + pub main_exe_alt_index: u16, // If log entry uses an alternative uuid file index (ex: absolute). This value gets prepended to the unknown_pc_id/offset +} + +impl FirehoseFormatters { + /// Identify formatter flags associated with the log entry. Formatter flags determine the file where the base format string is located + pub fn firehose_formatter_flags<'a>( + data: &'a [u8], + firehose_flags: &u16, + ) -> nom::IResult<&'a [u8], FirehoseFormatters> { + let mut formatter_flags = FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }; + let message_strings_uuid: u16 = 0x2; // main_exe flag + let large_shared_cache = 0xc; // large_shared_cache flag + let large_offset = 0x20; // has_large_offset flag + + let flag_check = 0xe; + let mut input = data; + + /* + 0x20 - has_large_offset flag. Offset to format string is larger than normal + 0xc - has_large_shared_cache flag. Offset to format string is larger than normal + 0x8 - absolute flag. The log uses an alterantive index number that points to the UUID file name in the Catalog which contains the format string + 0x2 - main_exe flag. A UUID file contains the format string + 0x4 - shared_cache flag. DSC file contains the format string + 0xa - uuid_relative flag. The UUID file name is in the log data (instead of the Catalog) + */ + match firehose_flags & flag_check { + 0x20 => { + debug!("[macos-unifiedlogs] Firehose flag: has_large_offset"); + let (firehose_input, large_offset_data) = take(size_of::())(input)?; + let (_, firehose_large_offset) = le_u16(large_offset_data)?; + formatter_flags.has_large_offset = firehose_large_offset; + input = firehose_input; + if (firehose_flags & large_shared_cache) != 0 { + debug!("[macos-unifiedlogs] Firehose flag: large_shared_cache and has_large_offset"); + let (firehose_input, large_shared_cache) = + take(size_of::())(firehose_input)?; + let (_, firehose_large_shared_cache) = le_u16(large_shared_cache)?; + formatter_flags.large_shared_cache = firehose_large_shared_cache; + input = firehose_input; + } + } + 0xc => { + debug!("[macos-unifiedlogs] Firehose flag: large_shared_cache"); + if (firehose_flags & large_offset) != 0 { + let (firehose_input, large_offset_data) = take(size_of::())(input)?; + let (_, firehose_large_offset) = le_u16(large_offset_data)?; + formatter_flags.has_large_offset = firehose_large_offset; + input = firehose_input; + } + + let (firehose_input, large_shared_cache) = take(size_of::())(input)?; + let (_, firehose_large_shared_cache) = le_u16(large_shared_cache)?; + formatter_flags.large_shared_cache = firehose_large_shared_cache; + input = firehose_input; + } + 0x8 => { + debug!("[macos-unifiedlogs] Firehose flag: absolute"); + formatter_flags.absolute = true; + if (firehose_flags & message_strings_uuid) == 0 { + debug!("[macos-unifiedlogs] Firehose flag: alt index absolute flag"); + let (firehose_input, uuid_file_index) = take(size_of::())(input)?; + let (_, firehose_uuid_file_index) = le_u16(uuid_file_index)?; + + formatter_flags.main_exe_alt_index = firehose_uuid_file_index; + input = firehose_input; + } + } + 0x2 => { + debug!("[macos-unifiedlogs] Firehose flag: main_exe"); + formatter_flags.main_exe = true + } + 0x4 => { + debug!("[macos-unifiedlogs] Firehose flag: shared_cache"); + formatter_flags.shared_cache = true; + if (firehose_flags & large_offset) != 0 { + let (firehose_input, large_offset_data) = take(size_of::())(input)?; + let (_, firehose_large_offset) = le_u16(large_offset_data)?; + formatter_flags.has_large_offset = firehose_large_offset; + input = firehose_input; + } + } + 0xa => { + debug!("[macos-unifiedlogs] Firehose flag: uuid_relative"); + let (firehose_input, uuid_relative) = take(size_of::())(input)?; + let (_, firehose_uuid_relative) = be_u128(uuid_relative)?; + formatter_flags.uuid_relative = format!("{:X}", firehose_uuid_relative); + input = firehose_input; + } + _ => { + error!( + "[macos-unifiedlogs] Unknown Firehose formatter flag: {:?}", + firehose_flags + ); + debug!("[macos-unifiedlogs] Firehose data: {:X?}", data); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + Ok((input, formatter_flags)) + } +} + +#[cfg(test)] +mod tests { + use crate::chunks::firehose::flags::FirehoseFormatters; + + #[test] + fn test_firehose_formatter_flags_has_large_offset() { + let test_data = [ + 1, 0, 2, 0, 14, 0, 34, 2, 0, 4, 135, 16, 0, 0, 34, 4, 0, 0, 5, 0, 100, 101, 110, 121, 0, + ]; + let test_flags = 557; + let (_, results) = + FirehoseFormatters::firehose_formatter_flags(&test_data, &test_flags).unwrap(); + assert_eq!(results.has_large_offset, 1); + assert_eq!(results.large_shared_cache, 2); + } + + #[test] + fn test_firehose_formatter_flags_message_strings_uuid_message_alt_index() { + let test_data = [8, 0, 17, 166, 251, 2, 128, 255, 0, 0]; + let test_flags = 8; + let (_, results) = + FirehoseFormatters::firehose_formatter_flags(&test_data, &test_flags).unwrap(); + assert_eq!(results.main_exe_alt_index, 8) + } + + #[test] + fn test_firehose_formatter_flags_message_strings_uuid() { + let test_data = [186, 0, 0, 0]; + let test_flags = 514; + let (_, results) = + FirehoseFormatters::firehose_formatter_flags(&test_data, &test_flags).unwrap(); + assert_eq!(results.main_exe, true); + } + + #[test] + fn test_firehose_formatter_flags_shared_cache_dsc_uuid() { + let test_data = [ + 23, 1, 34, 1, 66, 4, 0, 0, 35, 0, 83, 65, 83, 83, 101, 115, 115, 105, 111, 110, 83, + 116, 97, 116, 101, 70, 111, 114, 85, 115, 101, 114, 58, 49, 50, 52, 54, 58, 32, 101, + 110, 116, 101, 114, 0, + ]; + let test_flags = 516; + let (_, results) = + FirehoseFormatters::firehose_formatter_flags(&test_data, &test_flags).unwrap(); + assert_eq!(results.shared_cache, true); + } + + #[test] + fn test_firehose_formatter_flags_absolute_message_alt_uuid() { + let test_data = [ + 128, 255, 2, 13, 34, 4, 0, 0, 6, 0, 34, 4, 6, 0, 11, 0, 34, 4, 17, 0, 7, 0, 2, 4, 8, 0, + 0, 0, 2, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 2, 8, 0, 0, 0, 0, 0, 0, 0, 0, 34, + 4, 24, 0, 3, 0, 34, 4, 27, 0, 3, 0, 2, 8, 156, 17, 7, 98, 0, 0, 0, 0, 2, 8, 156, 17, 7, + 98, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 34, 4, 30, 0, 3, 0, 65, 67, 77, 82, 77, 0, 95, 108, + 111, 103, 80, 111, 108, 105, 99, 121, 0, 83, 65, 86, 73, 78, 71, 0, 78, 79, 0, 78, 79, + 0, 78, 79, 0, + ]; + let test_flags = 8; + let (_, results) = + FirehoseFormatters::firehose_formatter_flags(&test_data, &test_flags).unwrap(); + assert_eq!(results.absolute, true); + assert_eq!(results.main_exe_alt_index, 65408); + } + + #[test] + fn test_firehose_formatter_flags_uuid_relative() { + let test_data = [ + 123, 13, 55, 117, 241, 144, 62, 33, 186, 19, 4, 71, 196, 27, 135, 67, 0, 0, + ]; + let test_flags = 0xa; + let (_, results) = + FirehoseFormatters::firehose_formatter_flags(&test_data, &test_flags).unwrap(); + assert_eq!(results.uuid_relative, "7B0D3775F1903E21BA130447C41B8743"); + } +} diff --git a/src/chunks/firehose/loss.rs b/src/chunks/firehose/loss.rs new file mode 100755 index 0000000..64ca2a1 --- /dev/null +++ b/src/chunks/firehose/loss.rs @@ -0,0 +1,60 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use nom::bytes::complete::take; +use nom::number::complete::le_u64; +use std::mem::size_of; + +#[derive(Debug, Clone)] +pub struct FirehoseLoss { + pub start_time: u64, + pub end_time: u64, + pub count: u64, +} + +impl FirehoseLoss { + /// Parse loss Firehose log entry. + // Ex: tp 16 + 48: loss + pub fn parse_firehose_loss(data: &[u8]) -> nom::IResult<&[u8], FirehoseLoss> { + let mut firehose_loss = FirehoseLoss { + start_time: 0, + end_time: 0, + count: 0, + }; + + let (input, start_time) = take(size_of::())(data)?; + let (input, end_time) = take(size_of::())(input)?; + let (input, count) = take(size_of::())(input)?; + + let (_, firehose_start_time) = le_u64(start_time)?; + let (_, firehose_end_time) = le_u64(end_time)?; + let (_, firehose_count) = le_u64(count)?; + + firehose_loss.start_time = firehose_start_time; + firehose_loss.end_time = firehose_end_time; + firehose_loss.count = firehose_count; + + Ok((input, firehose_loss)) + } +} + +#[cfg(test)] +mod tests { + use crate::chunks::firehose::loss::FirehoseLoss; + + #[test] + fn test_parse_firehose_loss_monterey() { + let test_data = [ + 72, 56, 43, 42, 0, 0, 0, 0, 231, 207, 114, 187, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, + ]; + + let (_, results) = FirehoseLoss::parse_firehose_loss(&test_data).unwrap(); + assert_eq!(results.start_time, 707475528); + assert_eq!(results.end_time, 3144863719); + assert_eq!(results.count, 63); + } +} diff --git a/src/chunks/firehose/message.rs b/src/chunks/firehose/message.rs new file mode 100644 index 0000000..b0daeb8 --- /dev/null +++ b/src/chunks/firehose/message.rs @@ -0,0 +1,1071 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::{debug, info, warn}; +use nom::bytes::complete::take; + +use crate::catalog::CatalogChunk; +use crate::dsc::SharedCacheStrings; +use crate::util::extract_string; +use crate::uuidtext::{UUIDText, UUIDTextEntry}; + +#[derive(Debug)] +pub struct MessageData { + pub library: String, + pub format_string: String, + pub process: String, + pub library_uuid: String, + pub process_uuid: String, +} + +// Functions to help extract base format string based on flags associated with log entries +// Ex: "%s start" +impl MessageData { + /// Extract string from the Shared Strings Cache (dsc data) + // Shared strings contain library and message string + pub fn extract_shared_strings<'a>( + shared_strings: &'a [SharedCacheStrings], + strings_data: &'a [UUIDText], + string_offset: u64, + first_proc_id: &u64, + second_proc_id: &u32, + catalogs: &CatalogChunk, + has_large_offset: u16, + ) -> nom::IResult<&'a [u8], MessageData> { + debug!("[macos-unifiedlogs] Extracting format string from shared cache file (dsc)"); + let mut message_data = MessageData { + library: String::new(), + format_string: String::new(), + process: String::new(), + library_uuid: String::new(), + process_uuid: String::new(), + }; + + // Check if the string offset is "dynamic" (the formatter is "%s") + if (string_offset & 0x80000000 != 0) && has_large_offset == 0 { + for shared_string in shared_strings { + // Get shared string file (DSC) associated with log entry from Catalog + let (dsc_uuid, main_uuid) = + MessageData::get_catalog_dsc(catalogs, first_proc_id, second_proc_id); + if shared_string.dsc_uuid != dsc_uuid { + continue; + } + + if let Some(ranges) = shared_string.ranges.get(0) { + message_data.library = shared_string.uuids[ranges.unknown_uuid_index as usize] + .path_string + .to_owned(); + message_data.library_uuid = shared_string.uuids + [ranges.unknown_uuid_index as usize] + .uuid + .to_owned(); + message_data.format_string = String::from("%s"); + message_data.process_uuid = main_uuid; + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + + return Ok((&[], message_data)); + } + } + } + + // Go through shared strings collections + for shared_string in shared_strings { + // Get shared string file (DSC) associated with log entry from Catalog + let (dsc_uuid, main_uuid) = + MessageData::get_catalog_dsc(catalogs, first_proc_id, second_proc_id); + if shared_string.dsc_uuid != dsc_uuid { + continue; + } + debug!( + "[macos-unifiedlogs] Associated dsc file with log entry: {:?}", + dsc_uuid + ); + + for ranges in &shared_string.ranges { + if string_offset >= ranges.range_offset + && string_offset < (ranges.range_offset + u64::from(ranges.range_size)) + { + let offset = string_offset - ranges.range_offset; + let strings = &ranges.strings; + let string_data: &[u8] = strings; + + // If the offset and string data are equal then the next range entry contains the string message + /* If offset = 2800, then the entry would be in range 322 (range 321 ends at 0x00000b04bfc0 and range 322 starts at 0x00000b04bfc0 ) + Range 321: + uuid 208: 6B77361F-69AF-393F-97B8-9BDED38304B0 + dsc range: 0x00000b04b4d0 .. 0x00000b04bfc0 (2800) + path: /System/Library/PrivateFrameworks/IconFoundation.framework/Versions/A/IconFoundation + + Range 322: + uuid 208: 6B77361F-69AF-393F-97B8-9BDED38304B0 + dsc range: 0x00000b04bfc0 .. 0x00000b04c0ac (236) + path: /System/Library/PrivateFrameworks/IconFoundation.framework/Versions/A/IconFoundation + */ + if offset as usize == string_data.len() { + continue; + } + + let (message_start, _) = take(offset)(string_data)?; + let (_, message_string) = extract_string(message_start)?; + message_data.format_string = message_string; + + message_data.library = shared_string.uuids[ranges.unknown_uuid_index as usize] + .path_string + .to_owned(); + message_data.library_uuid = shared_string.uuids + [ranges.unknown_uuid_index as usize] + .uuid + .to_owned(); + message_data.process_uuid = main_uuid; + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + return Ok((&[], message_data)); + } + } + } + + // There is a chance the log entry does not have a valid offset + // Apple reports as "~~> " or + for shared_string in shared_strings { + // Get shared string file (DSC) associated with log entry from Catalog + let (dsc_uuid, main_uuid) = + MessageData::get_catalog_dsc(catalogs, first_proc_id, second_proc_id); + if shared_string.dsc_uuid != dsc_uuid { + continue; + } + + // Still get the image path/library for the log entry + if let Some(ranges) = shared_string.ranges.get(0) { + message_data.library = shared_string.uuids[ranges.unknown_uuid_index as usize] + .path_string + .to_owned(); + message_data.library_uuid = shared_string.uuids[ranges.unknown_uuid_index as usize] + .uuid + .to_owned(); + message_data.format_string = String::from("Error: Invalid shared string offset"); + message_data.process_uuid = main_uuid; + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + + return Ok((&[], message_data)); + } + } + + warn!("[macos-unifiedlogs] Failed to get message string from Shared Strings DSC file"); + message_data.format_string = String::from("Unknown shared string message"); + + Ok((&[], message_data)) + } + + /// Extract strings from the `UUIDText` file associated with log entry + /// `UUIDText` file contains process and message string + pub fn extract_format_strings<'a>( + strings_data: &'a [UUIDText], + string_offset: u64, + first_proc_id: &u64, + second_proc_id: &u32, + catalogs: &CatalogChunk, + has_large_offset: u16, + ) -> nom::IResult<&'a [u8], MessageData> { + debug!("[macos-unifiedlogs] Extracting format string from UUID file"); + let (_, main_uuid) = MessageData::get_catalog_dsc(catalogs, first_proc_id, second_proc_id); + + // log entries with main_exe flag do not use dsc cache uuid file + let mut message_data = MessageData { + library: String::new(), + format_string: String::new(), + process: String::new(), + library_uuid: main_uuid.to_owned(), + process_uuid: main_uuid, + }; + + // If most significant bit is set, the string offset is "dynamic" (the formatter is "%s") + if (string_offset & 0x80000000 != 0) && has_large_offset == 0 { + for data in strings_data { + if message_data.process_uuid.ends_with(&data.uuid) { + // Footer data is a collection of strings that ends with the image path/library associated with strings + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + let (_, process_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + message_data.process = process_string.to_owned(); + message_data.library = process_string; + message_data.format_string = String::from("%s"); + + return Ok((&[], message_data)); + } + } + } + + // Go through the collection of parsed UUIDText files until matching UUID file is found + for data in strings_data { + if message_data.process_uuid.ends_with(&data.uuid) { + let mut string_start = 0; + for entry in &data.entry_descriptors { + // Identify start of string formatter offset + if entry.range_start_offset > string_offset as u32 { + string_start += entry.entry_size; + continue; + } + + let offset = string_offset as u32 - entry.range_start_offset; + // Footer data is a collection of strings that ends with the image path/library associated with strings + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + // Check to make sure footer/string data is larger than the offset + if (footer_data.len() < (offset + string_start) as usize) + || offset > entry.entry_size + { + string_start += entry.entry_size; + continue; + } + + let (message_start, _) = take(offset + string_start)(footer_data)?; + let (_, message_string) = extract_string(message_start)?; + + let (_, process_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + + message_data.format_string = message_string; + // Process and library path are the same for log entries with main_exe + message_data.process = process_string.to_owned(); + message_data.library = process_string; + + return Ok((&[], message_data)); + } + } + } + + // There is a chance the log entry does not have a valid offset + // Apple labels as "error: ~~> Invalid bounds 4334340 for E502E11E-518F-38A7-9F0B-E129168338E7" + for data in strings_data { + if message_data.process_uuid.ends_with(&data.uuid) { + // Footer data is a collection of strings that ends with the image process associated with the strings + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + let (_, process_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + message_data.process = process_string.to_owned(); + message_data.library = process_string; + message_data.format_string = format!( + "Error: Invalid offset {} for UUID {}", + string_offset, message_data.process_uuid + ); + + return Ok((&[], message_data)); + } + } + + warn!( + "[macos-unifiedlogs] Failed to get message string from UUIDText file: {}", + message_data.process_uuid + ); + message_data.format_string = format!( + "Failed to get string message from UUIDText file: {}", + message_data.process_uuid + ); + Ok((&[], message_data)) + } + + /// Extract strings from the `UUIDText` file associated with log entry that have `absolute` flag set + /// `UUIDText` file contains process and message string + pub fn extract_absolute_strings<'a>( + strings_data: &'a [UUIDText], + absolute_offset: u64, + string_offset: u64, + first_proc_id: &u64, + second_proc_id: &u32, + catalogs: &CatalogChunk, + has_large_offset: u16, + ) -> nom::IResult<&'a [u8], MessageData> { + debug!("[macos-unifiedlogs] Extracting format string from UUID file for log entry with Absolute flag"); + let mut uuid = String::new(); + // Go through Catalog associated with log entry and find UUID entry associated with log message (first_proc_id@second_proc_id) + for process_info in &catalogs.catalog_process_info_entries { + if first_proc_id == &process_info.first_number_proc_id + && second_proc_id == &process_info.second_number_proc_id + { + // In addition to first_proc_id and second_proc_id, we need to go through UUID entries in the catalog + // Entries with the Absolute flag have the UUID stored in an Vec of UUIDs and offsets/load_address + // The correct UUID entry is the one where the absolute_offset value falls in between load_address and load_address size (uuids.load_address + uuids.size) + for uuids in &process_info.uuid_info_entries { + if absolute_offset >= uuids.load_address + && absolute_offset <= (uuids.load_address + u64::from(uuids.size)) + { + debug!( + "[macos-unifiedlogs] Absolute uuid file is: {:?}", + uuids.uuid + ); + uuid = uuids.uuid.to_owned(); + break; + } + } + } + if !uuid.is_empty() { + break; + } + } + // The UUID for log entries with absolute flag dont use the dsc uuid files + let (_, main_uuid) = MessageData::get_catalog_dsc(catalogs, first_proc_id, second_proc_id); + + let mut message_data = MessageData { + library: String::new(), + format_string: String::new(), + process: String::new(), + library_uuid: uuid, + process_uuid: main_uuid, + }; + // If most significant bit is set, the string offset is "dynamic" (the formatter is "%s") + if ((string_offset & 0x80000000 != 0) || string_offset == absolute_offset) + && has_large_offset == 0 + { + for data in strings_data { + if message_data.library_uuid.ends_with(&data.uuid) { + // Footer data is a collection of strings that ends with the image path/library associated with strings + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + // Extract image path from current UUIDtext file + let (_, library_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + message_data.library = library_string; + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + message_data.format_string = String::from("%s"); + + return Ok((&[], message_data)); + } + } + } + + for data in strings_data { + if message_data.library_uuid.ends_with(&data.uuid) { + let mut string_start = 0; + for entry in &data.entry_descriptors { + // Identify start of string formatter offset + if u64::from(entry.range_start_offset) > string_offset { + string_start += entry.entry_size; + continue; + } + + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + let offset = string_offset - u64::from(entry.range_start_offset); + // Check to make sure footer/string data is larger than the offset + if (footer_data.len() < (offset + u64::from(string_start)) as usize) + || offset > u64::from(entry.entry_size) + { + string_start += entry.entry_size; + continue; + } + let (message_start, _) = take(offset + u64::from(string_start))(footer_data)?; + let (_, message_string) = extract_string(message_start)?; + + // Extract image path from current UUIDtext file + let (_, library_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + message_data.format_string = message_string; + message_data.library = library_string; + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + return Ok((&[], message_data)); + } + } + } + + // There is a chance the log entry does not have a valid offset + // Apple labels as "error: ~~> Invalid bounds 4334340 for E502E11E-518F-38A7-9F0B-E129168338E7" + for data in strings_data { + if message_data.library_uuid.ends_with(&data.uuid) { + // Footer data is a collection of strings that ends with the image process associated with the strings + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + // Extract image path from current UUIDtext file + let (_, library_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + message_data.library = library_string; + message_data.format_string = format!( + "Error: Invalid offset {} for absolute UUID {}", + string_offset, message_data.library_uuid + ); + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + + return Ok((&[], message_data)); + } + } + + warn!( + "[macos-unifiedlogs] Failed to get message string from absolute UUIDText file: {}", + message_data.library_uuid + ); + message_data.format_string = format!( + "Failed to get string message from absolute UUIDText file: {}", + message_data.library_uuid + ); + Ok((&[], message_data)) + } + + /// Extract strings from an alt `UUIDText` file specified within the log entry that have `uuid_relative` flag set + /// `UUIDText` files contains library and process and message string + pub fn extract_alt_uuid_strings<'a>( + strings_data: &'a [UUIDText], + string_offset: u64, + uuid: &str, + first_proc_id: &u64, + second_proc_id: &u32, + catalogs: &CatalogChunk, + has_large_offset: u16, + ) -> nom::IResult<&'a [u8], MessageData> { + debug!("[macos-unifiedlogs] Extracting format string from alt uuid"); + // Log entries with uuid_relative flags set have the UUID in the log itself. They do not use the dsc UUID files + let (_, main_uuid) = MessageData::get_catalog_dsc(catalogs, first_proc_id, second_proc_id); + + let mut message_data = MessageData { + library: String::new(), + format_string: String::new(), + process: String::new(), + library_uuid: uuid.to_string(), + process_uuid: main_uuid, + }; + // If most significant bit is set, the string offset is "dynamic" (the formatter is "%s") + if (string_offset & 0x80000000 != 0) && has_large_offset == 0 { + for data in strings_data { + if uuid.ends_with(&data.uuid) { + // Footer data is a collection of strings that ends with the image path/library associated with strings + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + // Extract image path from current UUIDtext file + let (_, library_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + message_data.library = library_string; + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + message_data.format_string = String::from("%s"); + + return Ok((&[], message_data)); + } + } + } + + for data in strings_data { + if uuid.ends_with(&data.uuid) { + let mut string_start = 0; + for entry in &data.entry_descriptors { + // Identify start of string formatter offset + if entry.range_start_offset > string_offset as u32 { + string_start += entry.entry_size; + continue; + } + let offset = string_offset as u32 - entry.range_start_offset; + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + // Check to make sure footer/string data is larger than the offset + // Or if the offset is greater than the entry size + // If offset greater than entry size then its not the correct UUIDText entry + if (footer_data.len() < offset as usize) || offset > entry.entry_size { + string_start += entry.entry_size; + continue; + } + let (message_start, _) = take(offset + string_start)(footer_data)?; + let (_, message_string) = extract_string(message_start)?; + + // Extract image path from current UUIDtext file + let (_, library_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + + message_data.format_string = message_string; + message_data.library = library_string; + return Ok((&[], message_data)); + } + } + } + + // There is a chance the log entry does not have a valid offset + // Apple labels as "error: ~~> Invalid bounds 4334340 for E502E11E-518F-38A7-9F0B-E129168338E7" + for data in strings_data { + if uuid.ends_with(&data.uuid) { + // Footer data is a collection of strings that ends with the image process associated with the strings + let strings = &data.footer_data; + let footer_data: &[u8] = strings; + + // Extract image path from current UUIDtext file + let (_, library_string) = + MessageData::uuidtext_image_path(footer_data, &data.entry_descriptors)?; + message_data.library = library_string; + message_data.format_string = format!( + "Error: Invalid offset {} for alternative UUID {}", + string_offset, uuid + ); + + // Extract image path from second UUIDtext file + let (_, process_string) = + MessageData::get_uuid_image_path(&message_data.process_uuid, strings_data)?; + message_data.process = process_string; + + return Ok((&[], message_data)); + } + } + + warn!( + "[macos-unifiedlogs] Failed to get message string from alternative UUIDText file: {}", + uuid + ); + message_data.format_string = format!( + "Failed to get string message from alternative UUIDText file: {}", + uuid + ); + Ok((&[], message_data)) + } + + /// Get the image path at the end of the `UUIDText` file + fn uuidtext_image_path<'a>( + data: &'a [u8], + entries: &[UUIDTextEntry], + ) -> nom::IResult<&'a [u8], String> { + // Add up all entry range offset sizes to get image library offset + let mut image_library_offest: u32 = 0; + for entry in entries { + image_library_offest += entry.entry_size; + } + let (library_start, _) = take(image_library_offest)(data)?; + extract_string(library_start) + } + + /// Get the image path from provided `main_uuid` entry + fn get_uuid_image_path<'a>( + main_uuid: &str, + entries: &'a [UUIDText], + ) -> nom::IResult<&'a [u8], String> { + for data in entries { + if main_uuid.ends_with(&data.uuid) { + return MessageData::uuidtext_image_path( + &data.footer_data, + &data.entry_descriptors, + ); + } + } + // An UUID of all zeros is possilbe in the Catalog, if this happens there is no process path + if main_uuid == "00000000000000000000000000000000" { + info!("[macos-unifiedlogs] Got UUID of all zeros fom Catalog"); + return Ok((&[], String::new())); + } + warn!( + "[macos-unifiedlogs] Failed to get path string from UUIDText file for entry: {}", + main_uuid + ); + + Ok(( + &[], + format!( + "Failed to get path string from UUIDText file for entry: {}", + main_uuid + ), + )) + } + + // Grab dsc file name from the Catalog data based on first and second proc ids from the Firehose log + fn get_catalog_dsc( + catalogs: &CatalogChunk, + first_proc_id: &u64, + second_proc_id: &u32, + ) -> (String, String) { + let mut dsc_uuid = String::new(); + let mut main_uuid = String::new(); + + for process_info in &catalogs.catalog_process_info_entries { + if first_proc_id == &process_info.first_number_proc_id + && second_proc_id == &process_info.second_number_proc_id + { + dsc_uuid = process_info.dsc_uuid.to_owned(); + main_uuid = process_info.main_uuid.to_owned(); + break; + } + } + (dsc_uuid, main_uuid) + } +} + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use crate::{ + chunks::firehose::message::MessageData, + parser::{collect_shared_strings, collect_strings, parse_log}, + }; + + #[test] + fn test_extract_shared_strings_nonactivity() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let test_offset = 1331408102; + let test_first_proc_id = 45; + let test_second_proc_id = 188; + + let (_, results) = MessageData::extract_shared_strings( + &shared_strings_results, + &strings, + test_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[0].catalog, + 0, + ) + .unwrap(); + assert_eq!( + results.library, + "/System/Library/PrivateFrameworks/AppleLOM.framework/Versions/A/AppleLOM" + ); + assert_eq!(results.library_uuid, "D8E5AF1CAF4F3CEB8731E6F240E8EA7D"); + + assert_eq!(results.process, "/usr/libexec/lightsoutmanagementd"); + assert_eq!(results.process_uuid, "6C3ADF991F033C1C96C4ADFAA12D8CED"); + + assert_eq!(results.format_string, "%@ start") + } + + #[test] + fn test_extract_shared_strings_nonactivity_bad_offset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let bad_offset = 7; + let test_first_proc_id = 45; + let test_second_proc_id = 188; + + let (_, results) = MessageData::extract_shared_strings( + &shared_strings_results, + &strings, + bad_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[0].catalog, + 0, + ) + .unwrap(); + assert_eq!(results.library, "/usr/lib/system/libsystem_blocks.dylib"); + assert_eq!(results.library_uuid, "4DF6D8F5D9C23A968DE45E99D6B73DC8"); + + assert_eq!(results.process, "/usr/libexec/lightsoutmanagementd"); + assert_eq!(results.process_uuid, "6C3ADF991F033C1C96C4ADFAA12D8CED"); + + assert_eq!(results.format_string, "Error: Invalid shared string offset") + } + + #[test] + fn test_extract_shared_strings_nonactivity_dynamic() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let test_offset = 2420246585; + let test_first_proc_id = 32; + let test_second_proc_id = 424; + let (_, results) = MessageData::extract_shared_strings( + &shared_strings_results, + &strings, + test_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[2].catalog, + 0, + ) + .unwrap(); + + assert_eq!(results.library, "/usr/lib/system/libsystem_blocks.dylib"); + assert_eq!(results.library_uuid, "4DF6D8F5D9C23A968DE45E99D6B73DC8"); + + assert_eq!( + results.process, + "/Library/Apple/System/Library/CoreServices/MRT.app/Contents/MacOS/MRT" + ); + assert_eq!(results.process_uuid, "95A48BD740423BEFBA6E0818A2EED8BE"); + + assert_eq!(results.format_string, "%s") + } + + #[test] + fn test_extract_format_strings_nonactivity() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let test_offset = 14960; + let test_first_proc_id = 45; + let test_second_proc_id = 188; + let (_, results) = MessageData::extract_format_strings( + &strings, + test_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[0].catalog, + 0, + ) + .unwrap(); + + assert_eq!(results.process, "/usr/libexec/lightsoutmanagementd"); + assert_eq!(results.process_uuid, "6C3ADF991F033C1C96C4ADFAA12D8CED"); + + assert_eq!(results.library, "/usr/libexec/lightsoutmanagementd"); + assert_eq!(results.library_uuid, "6C3ADF991F033C1C96C4ADFAA12D8CED"); + + assert_eq!(results.format_string, "LOMD Start") + } + + #[test] + fn test_extract_format_strings_nonactivity_bad_offset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let bad_offset = 1; + let test_first_proc_id = 45; + let test_second_proc_id = 188; + let (_, results) = MessageData::extract_format_strings( + &strings, + bad_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[0].catalog, + 0, + ) + .unwrap(); + + assert_eq!(results.process, "/usr/libexec/lightsoutmanagementd"); + assert_eq!( + results.format_string, + "Error: Invalid offset 1 for UUID 6C3ADF991F033C1C96C4ADFAA12D8CED" + ) + } + + #[test] + fn test_extract_format_strings_nonactivity_dynamic() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let test_offset = 2147519968; + let test_first_proc_id = 38; + let test_second_proc_id = 317; + let (_, results) = MessageData::extract_format_strings( + &strings, + test_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[4].catalog, + 0, + ) + .unwrap(); + + assert_eq!(results.process, "/System/Library/PrivateFrameworks/SystemAdministration.framework/Versions/A/Resources/UpdateSettingsTool"); + assert_eq!(results.process_uuid, "6F2A273A77993A719F649607CADC090B"); + + assert_eq!(results.library, "/System/Library/PrivateFrameworks/SystemAdministration.framework/Versions/A/Resources/UpdateSettingsTool"); + assert_eq!(results.library_uuid, "6F2A273A77993A719F649607CADC090B"); + + assert_eq!(results.format_string, "%s") + } + + #[test] + fn test_extract_format_strings_nonactivity_dynamic_bad_offset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let bad_offset = 55; + let test_first_proc_id = 38; + let test_second_proc_id = 317; + let (_, results) = MessageData::extract_format_strings( + &strings, + bad_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[4].catalog, + 0, + ) + .unwrap(); + + assert_eq!(results.process, "/System/Library/PrivateFrameworks/SystemAdministration.framework/Versions/A/Resources/UpdateSettingsTool"); + assert_eq!( + results.format_string, + "Error: Invalid offset 55 for UUID 6F2A273A77993A719F649607CADC090B" + ) + } + + #[test] + fn test_extract_absolute_strings_nonactivity() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let test_offset = 396912; + let test_absolute_offset = 280925241119206; + let test_first_proc_id = 0; + let test_second_proc_id = 0; + let (_, results) = MessageData::extract_absolute_strings( + &strings, + test_absolute_offset, + test_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[0].catalog, + 0, + ) + .unwrap(); + assert_eq!( + results.library, + "/System/Library/Extensions/AppleACPIPlatform.kext/Contents/MacOS/AppleACPIPlatform" + ); + assert_eq!(results.format_string, "%s") + } + + #[test] + fn test_extract_absolute_strings_nonactivity_bad_offset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let test_offset = 396912; + let bad_offset = 12; + let test_first_proc_id = 0; + let test_second_proc_id = 0; + let (_, results) = MessageData::extract_absolute_strings( + &strings, + bad_offset, + test_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[0].catalog, + 0, + ) + .unwrap(); + assert_eq!(results.library, ""); + assert_eq!( + results.format_string, + "Failed to get string message from absolute UUIDText file: " + ) + } + + #[test] + fn test_extract_absolute_strings_nonactivity_dynamic() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let test_offset = 102; + let test_absolute_offset = 102; + assert_eq!(log_data.catalog_data.len(), 56); + + let test_first_proc_id = 0; + let test_second_proc_id = 0; + let (_, results) = MessageData::extract_absolute_strings( + &strings, + test_absolute_offset, + test_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[1].catalog, + 0, + ) + .unwrap(); + + assert_eq!( + results.library, + "/System/Library/DriverExtensions/com.apple.AppleUserHIDDrivers.dext/" + ); + assert_eq!(results.format_string, "%s") + } + + #[test] + fn test_extract_absolute_strings_nonactivity_dynamic_bad_offset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let bad_offset = 111; + let test_absolute_offset = 102; + assert_eq!(log_data.catalog_data.len(), 56); + + let test_first_proc_id = 0; + let test_second_proc_id = 0; + let (_, results) = MessageData::extract_absolute_strings( + &strings, + test_absolute_offset, + bad_offset, + &test_first_proc_id, + &test_second_proc_id, + &log_data.catalog_data[1].catalog, + 0, + ) + .unwrap(); + + assert_eq!( + results.library, + "/System/Library/DriverExtensions/com.apple.AppleUserHIDDrivers.dext/" + ); + assert_eq!( + results.format_string, + "Error: Invalid offset 111 for absolute UUID 0AB77111A2723F2697571948ECE9BDB5" + ) + } + + #[test] + fn test_extract_alt_uuid_strings() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + test_path.push("Persist/0000000000000005.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let first_proc_id = 105; + let second_proc_id = 240; + + let test_offset = 221408; + let test_uuid = "C275D5EEBAD43A86B74F16F3E62BF57D"; + let (_, results) = MessageData::extract_alt_uuid_strings( + &strings, + test_offset, + test_uuid, + &first_proc_id, + &second_proc_id, + &log_data.catalog_data[0].catalog, + 0, + ) + .unwrap(); + assert_eq!( + results.library, + "/System/Library/OpenDirectory/Modules/SystemCache.bundle/Contents/MacOS/SystemCache" + ); + assert_eq!(results.library_uuid, "C275D5EEBAD43A86B74F16F3E62BF57D"); + + assert_eq!(results.process, "/usr/libexec/opendirectoryd"); + assert_eq!(results.process_uuid, "B736DF1625F538248E9527A8CEC4991E"); + } + + #[test] + fn test_get_catalog_dsc() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let test_first_proc_id = 136; + let test_second_proc_id = 342; + let (dsc_uuid, main_uuid) = MessageData::get_catalog_dsc( + &log_data.catalog_data[0].catalog, + &test_first_proc_id, + &test_second_proc_id, + ); + + assert_eq!(dsc_uuid, "80896B329EB13A10A7C5449B15305DE2"); + assert_eq!(main_uuid, "87721013944F3EA7A42C604B141CCDAA"); + } + + #[test] + fn test_get_uuid_image_path() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let strings = collect_strings(&test_path.display().to_string()).unwrap(); + + let test_uuid = "B736DF1625F538248E9527A8CEC4991E"; + + let (_, image_path) = MessageData::get_uuid_image_path(&test_uuid, &strings).unwrap(); + + assert_eq!(image_path, "/usr/libexec/opendirectoryd"); + } +} diff --git a/src/chunks/firehose/mod.rs b/src/chunks/firehose/mod.rs new file mode 100644 index 0000000..63179ec --- /dev/null +++ b/src/chunks/firehose/mod.rs @@ -0,0 +1,15 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +pub mod activity; +pub mod firehose_log; +pub mod flags; +pub mod loss; +pub mod message; +pub mod nonactivity; +pub mod signpost; +pub mod trace; diff --git a/src/chunks/firehose/nonactivity.rs b/src/chunks/firehose/nonactivity.rs new file mode 100755 index 0000000..5748b06 --- /dev/null +++ b/src/chunks/firehose/nonactivity.rs @@ -0,0 +1,342 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use crate::catalog::CatalogChunk; +use crate::chunks::firehose::flags::FirehoseFormatters; +use crate::chunks::firehose::message::MessageData; +use crate::dsc::SharedCacheStrings; +use crate::uuidtext::UUIDText; +use log::{debug, error}; +use nom::Needed; +use nom::{ + bytes::complete::take, + number::complete::{le_u16, le_u32, le_u8}, +}; +use std::mem::size_of; + +#[derive(Debug, Clone)] +pub struct FirehoseNonActivity { + pub unknown_activity_id: u32, // if flag 0x0001 + pub unknown_sentinal: u32, // always 0x80000000? if flag 0x0001 + pub private_strings_offset: u16, // if flag 0x0100 + pub private_strings_size: u16, // if flag 0x0100 + pub unknown_message_string_ref: u32, // if flag 0x0008 + pub subsystem_value: u16, // if flag 0x200, has_subsystem + pub ttl_value: u8, // if flag 0x0400, has_rules + pub data_ref_value: u16, // if flag 0x0800, has_oversize + pub unknown_pc_id: u32, // Appears to be used to calculate string offset for firehose events with Absolute flag + pub firehose_formatters: FirehoseFormatters, +} + +impl FirehoseNonActivity { + /// Parse Non-Activity Type Firehose log entry. + // Ex: tp 728 + 202: log debug (has_current_aid, main_exe, has_subsystem, has_rules) + pub fn parse_non_activity<'a>( + data: &'a [u8], + firehose_flags: &u16, + ) -> nom::IResult<&'a [u8], FirehoseNonActivity> { + let mut non_activity = FirehoseNonActivity { + unknown_activity_id: 0, + unknown_sentinal: 0, + private_strings_offset: 0, + private_strings_size: 0, + unknown_message_string_ref: 0, + subsystem_value: 0, + ttl_value: 0, + data_ref_value: 0, + unknown_pc_id: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + }; + let mut input = data; + let activity_id_current: u16 = 0x1; // has_current_aid flag + + if (firehose_flags & activity_id_current) != 0 { + debug!("[macos-unifiedlogs] Non-Activity Firehose log chunk has has_current_aid flag"); + let (firehose_input, unknown_activity_id) = take(size_of::())(input)?; + let (firehose_input, unknown_sentinel) = take(size_of::())(firehose_input)?; + let (_, firehose_unknown_activity_id) = le_u32(unknown_activity_id)?; + let (_, firehose_unknown_sentinel) = le_u32(unknown_sentinel)?; + non_activity.unknown_activity_id = firehose_unknown_activity_id; + non_activity.unknown_sentinal = firehose_unknown_sentinel; + input = firehose_input; + } + + let private_string_range: u16 = 0x100; // has_private_data flag + // Entry has private string data. The private data is found after parsing all the public data first + if (firehose_flags & private_string_range) != 0 { + debug!("[macos-unifiedlogs] Non-Activity Firehose log chunk has has_private_data flag"); + let (firehose_input, private_strings_offset) = take(size_of::())(input)?; + let (firehose_input, private_strings_size) = take(size_of::())(firehose_input)?; + + let (_, firehose_private_strings_offset) = le_u16(private_strings_offset)?; + let (_, firehose_private_strings_size) = le_u16(private_strings_size)?; + + // Offset points to private string values found after parsing the public data. Size is the data size + non_activity.private_strings_offset = firehose_private_strings_offset; + non_activity.private_strings_size = firehose_private_strings_size; + input = firehose_input; + } + + let (input, unknown_pc_id) = take(size_of::())(input)?; + let (_, firehose_unknown_pc_id) = le_u32(unknown_pc_id)?; + non_activity.unknown_pc_id = firehose_unknown_pc_id; + + // Check for flags related to base string format location (shared string file (dsc) or UUID file) + let (mut input, formatters) = + FirehoseFormatters::firehose_formatter_flags(input, firehose_flags)?; + non_activity.firehose_formatters = formatters; + + let subsystem: u16 = 0x200; // has_subsystem flag. In Non-Activity log entries this is the subsystem flag + if (firehose_flags & subsystem) != 0 { + debug!("[macos-unifiedlogs] Non-Activity Firehose log chunk has has_subsystem flag"); + let (firehose_input, subsystem) = take(size_of::())(input)?; + let (_, firehose_subsystem) = le_u16(subsystem)?; + non_activity.subsystem_value = firehose_subsystem; + input = firehose_input; + } + + let ttl: u16 = 0x400; // has_rules flag + if (firehose_flags & ttl) != 0 { + debug!("[macos-unifiedlogs] Non-Activity Firehose log chunk has has_rules flag"); + let (firehose_input, ttl_data) = take(size_of::())(input)?; + let (_, firehose_ttl) = le_u8(ttl_data)?; + non_activity.ttl_value = firehose_ttl; + input = firehose_input; + } + + let data_ref: u16 = 0x800; // has_oversize flag + if (firehose_flags & data_ref) != 0 { + debug!("[macos-unifiedlogs] Non-Activity Firehose log chunk has has_oversize flag"); + let (firehose_input, data_ref_value) = take(size_of::())(input)?; + let (_, firehose_data_ref) = le_u16(data_ref_value)?; + non_activity.data_ref_value = firehose_data_ref; + input = firehose_input; + } + + Ok((input, non_activity)) + } + + /// Get base log message string formatter from shared cache strings (dsc) or UUID text file for firehose non-activity log entries (chunks) + pub fn get_firehose_nonactivity_strings<'a>( + firehose: &FirehoseNonActivity, + strings_data: &'a [UUIDText], + shared_strings: &'a [SharedCacheStrings], + string_offset: u64, + first_proc_id: &u64, + second_proc_id: &u32, + catalogs: &CatalogChunk, + ) -> nom::IResult<&'a [u8], MessageData> { + if firehose.firehose_formatters.shared_cache + || (firehose.firehose_formatters.large_shared_cache != 0) + { + if firehose.firehose_formatters.has_large_offset != 0 { + let mut large_offset = firehose.firehose_formatters.has_large_offset; + // large_shared_cache should be double the value of has_large_offset + // Ex: has_large_offset = 1, large_shared_cache = 2 + // If the value do not match then there is an issue with shared string offset + // Can recover by using large_shared_cache + // Apple/log records this as an error: "error: ~~> " + // But is still able to get string formatter + if large_offset != firehose.firehose_formatters.large_shared_cache / 2 + && !firehose.firehose_formatters.shared_cache + { + large_offset = firehose.firehose_formatters.large_shared_cache / 2; + } else { + // Large offset is 8 if shared_cache flag is set + large_offset = 8; + } + + // Combine large offset value with current string offset to get the true offset + let extra_offset_value = format!("{:X}{:07X}", large_offset, string_offset); + let extra_offset_value_result = u64::from_str_radix(&extra_offset_value, 16); + + match extra_offset_value_result { + Ok(offset) => { + return MessageData::extract_shared_strings( + shared_strings, + strings_data, + offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + Err(err) => { + // We should not get errors since we are combining two numbers to create the offset + error!( + "Failed to get shared string offset to format string for non-activity firehose entry: {:?}", + err + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + } + MessageData::extract_shared_strings( + shared_strings, + strings_data, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ) + } else { + if firehose.firehose_formatters.absolute { + let extra_offset_value = format!( + "{:X}{:08X}", + firehose.firehose_formatters.main_exe_alt_index, firehose.unknown_pc_id + ); + + let offset_result = u64::from_str_radix(&extra_offset_value, 16); + match offset_result { + Ok(offset) => { + return MessageData::extract_absolute_strings( + strings_data, + offset, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + Err(err) => { + // We should not get errors since we are combining two numbers to create the offset + error!("Failed to get absolute offset to format string for non-activity firehose entry: {:?}", err); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + } + if !firehose.firehose_formatters.uuid_relative.is_empty() { + return MessageData::extract_alt_uuid_strings( + strings_data, + string_offset, + &firehose.firehose_formatters.uuid_relative, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + MessageData::extract_format_strings( + strings_data, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ) + } + } +} + +#[cfg(test)] +mod tests { + use super::FirehoseNonActivity; + use crate::parser::{collect_shared_strings, collect_strings, parse_log}; + use std::path::PathBuf; + + #[test] + fn test_parse_non_activity() { + let test_data = [ + 122, 179, 12, 13, 2, 0, 4, 0, 41, 0, 34, 9, 32, 4, 0, 0, 1, 0, 32, 4, 1, 0, 1, 0, 32, + 4, 2, 0, 14, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 100, 105, + 115, 112, 97, 116, 99, 104, 69, 118, 101, 110, 116, 0, + ]; + let test_flags = 556; + let (_, nonactivity_results) = + FirehoseNonActivity::parse_non_activity(&test_data, &test_flags).unwrap(); + assert_eq!(nonactivity_results.unknown_activity_id, 0); + assert_eq!(nonactivity_results.unknown_sentinal, 0); + assert_eq!(nonactivity_results.private_strings_offset, 0); + assert_eq!(nonactivity_results.private_strings_size, 0); + assert_eq!(nonactivity_results.unknown_message_string_ref, 0); + assert_eq!( + nonactivity_results.firehose_formatters.main_exe_alt_index, + 0 + ); + assert_eq!( + nonactivity_results.firehose_formatters.uuid_relative, + String::from("") + ); + assert_eq!(nonactivity_results.firehose_formatters.main_exe, false); + assert_eq!(nonactivity_results.firehose_formatters.absolute, false); + assert_eq!(nonactivity_results.subsystem_value, 41); + assert_eq!(nonactivity_results.ttl_value, 0); + assert_eq!(nonactivity_results.data_ref_value, 0); + assert_eq!( + nonactivity_results.firehose_formatters.large_shared_cache, + 4 + ); + assert_eq!(nonactivity_results.firehose_formatters.has_large_offset, 2); + assert_eq!(nonactivity_results.unknown_pc_id, 218936186); + } + + #[test] + fn test_get_firehose_non_activity_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000004.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let activity_type = 0x4; + + for catalog_data in log_data.catalog_data { + for preamble in catalog_data.firehose { + for firehose in preamble.public_data { + if firehose.unknown_log_activity_type == activity_type { + let (_, message_data) = + FirehoseNonActivity::get_firehose_nonactivity_strings( + &firehose.firehose_non_activity, + &string_results, + &shared_strings_results, + firehose.format_string_location as u64, + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ) + .unwrap(); + assert_eq!( + message_data.format_string, + "opendirectoryd (build %{public}s) launched..." + ); + assert_eq!(message_data.library, "/usr/libexec/opendirectoryd"); + assert_eq!(message_data.process, "/usr/libexec/opendirectoryd"); + assert_eq!( + message_data.process_uuid, + "B736DF1625F538248E9527A8CEC4991E" + ); + assert_eq!( + message_data.library_uuid, + "B736DF1625F538248E9527A8CEC4991E" + ); + return; + } + } + } + } + } +} diff --git a/src/chunks/firehose/signpost.rs b/src/chunks/firehose/signpost.rs new file mode 100755 index 0000000..d9047ba --- /dev/null +++ b/src/chunks/firehose/signpost.rs @@ -0,0 +1,350 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use crate::catalog::CatalogChunk; +use crate::chunks::firehose::flags::FirehoseFormatters; +use crate::chunks::firehose::message::MessageData; +use crate::dsc::SharedCacheStrings; +use crate::uuidtext::UUIDText; +use log::{debug, error}; +use nom::bytes::complete::take; +use nom::number::complete::{le_u16, le_u32, le_u64, le_u8}; +use nom::Needed; +use std::mem::size_of; + +#[derive(Debug, Clone)] +pub struct FirehoseSignpost { + pub unknown_pc_id: u32, // Appears to be used to calculate string offset for firehose events with Absolute flag + pub unknown_activity_id: u32, + pub unknown_sentinel: u32, + pub subsystem: u16, + pub signpost_id: u64, + pub signpost_name: u32, + pub private_strings_offset: u16, // if flag 0x0100 + pub private_strings_size: u16, // if flag 0x0100 + pub ttl_value: u8, + pub data_ref_value: u16, // if flag 0x0800, has_oversize + pub firehose_formatters: FirehoseFormatters, +} + +impl FirehoseSignpost { + /// Parse Signpost Firehose log entry. + // Ex: tp 2368 + 92: process signpost event (shared_cache, has_name, has_subsystem) + pub fn parse_signpost<'a>( + data: &'a [u8], + firehose_flags: &u16, + ) -> nom::IResult<&'a [u8], FirehoseSignpost> { + let mut firehose_signpost = FirehoseSignpost { + unknown_pc_id: 0, + unknown_activity_id: 0, + unknown_sentinel: 0, + subsystem: 0, + signpost_id: 0, + signpost_name: 0, + private_strings_offset: 0, + private_strings_size: 0, + ttl_value: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + data_ref_value: 0, + }; + + let mut input = data; + + let activity_id_current: u16 = 0x1; // has_current_aid flag + if (firehose_flags & activity_id_current) != 0 { + debug!("[macos-unifiedlogs] Signpost Firehose has has_current_aid flag"); + let (firehose_input, unknown_activity_id) = take(size_of::())(input)?; + let (firehose_input, unknown_sentinel) = take(size_of::())(firehose_input)?; + let (_, firehose_unknown_activity_id) = le_u32(unknown_activity_id)?; + let (_, firehose_unknown_sentinel) = le_u32(unknown_sentinel)?; + firehose_signpost.unknown_activity_id = firehose_unknown_activity_id; + firehose_signpost.unknown_sentinel = firehose_unknown_sentinel; + input = firehose_input; + } + + let private_string_range: u16 = 0x100; // has_private_data flag + // Entry has private string data. The private data is found after parsing all the public data first + if (firehose_flags & private_string_range) != 0 { + debug!("[macos-unifiedlogs] Signpost Firehose has has_private_data flag"); + let (firehose_input, private_strings_offset) = take(size_of::())(input)?; + let (firehose_input, private_strings_size) = take(size_of::())(firehose_input)?; + + let (_, firehose_private_strings_offset) = le_u16(private_strings_offset)?; + let (_, firehose_private_strings_size) = le_u16(private_strings_size)?; + + // Offset points to private string values found after parsing the public data. Size is the data size + firehose_signpost.private_strings_offset = firehose_private_strings_offset; + firehose_signpost.private_strings_size = firehose_private_strings_size; + input = firehose_input; + } + + let (input, unknown_pc_id) = take(size_of::())(input)?; + let (_, firehose_unknown_pc_id) = le_u32(unknown_pc_id)?; + firehose_signpost.unknown_pc_id = firehose_unknown_pc_id; + + // Check for flags related to base string format location (shared string file (dsc) or UUID file) + let (mut input, formatters) = + FirehoseFormatters::firehose_formatter_flags(input, firehose_flags)?; + firehose_signpost.firehose_formatters = formatters; + + let subsystem: u16 = 0x200; // has_subsystem flag. In Signpost log entries this is the subsystem flag + if (firehose_flags & subsystem) != 0 { + debug!("[macos-unifiedlogs] Signpost Firehose log chunk has has_subsystem flag"); + let (firehose_input, subsystem) = take(size_of::())(input)?; + let (_, firehose_subsystem) = le_u16(subsystem)?; + firehose_signpost.subsystem = firehose_subsystem; + input = firehose_input; + } + let (mut input, signpost_id) = take(size_of::())(input)?; + let (_, firehose_signpost_id) = le_u64(signpost_id)?; + firehose_signpost.signpost_id = firehose_signpost_id; + + let has_rules: u16 = 0x400; // has_rules flag + if (firehose_flags & has_rules) != 0 { + debug!("[macos-unifiedlogs] Signpost Firehose log chunk has has_rules flag"); + let (firehose_input, ttl_data) = take(size_of::())(input)?; + let (_, firehose_ttl) = le_u8(ttl_data)?; + firehose_signpost.ttl_value = firehose_ttl; + input = firehose_input; + } + + let data_ref: u16 = 0x800; // has_oversize flag + if (firehose_flags & data_ref) != 0 { + debug!("[macos-unifiedlogs] Signpost Firehose log chunk has has_oversize flag"); + let (firehose_input, data_ref_value) = take(size_of::())(input)?; + let (_, firehose_data_ref) = le_u16(data_ref_value)?; + firehose_signpost.data_ref_value = firehose_data_ref; + input = firehose_input; + } + + let has_name = 0x8000; + if (firehose_flags & has_name) != 0 { + debug!("[macos-unifiedlogs] Signpost Firehose log chunk has has_name flag"); + let (firehose_input, signpost_name) = take(size_of::())(input)?; + let (_, firehose_signpost_name) = le_u32(signpost_name)?; + firehose_signpost.signpost_name = firehose_signpost_name; + input = firehose_input; + // If the signpost log has large_shared_cache flag + // Then the signpost name has the same value after as the large_shared_cache + if firehose_signpost.firehose_formatters.large_shared_cache != 0 { + let (firehose_input, _) = take(size_of::())(input)?; + input = firehose_input; + } + } + + Ok((input, firehose_signpost)) + } + + /// Get base log message string formatter from shared cache strings (dsc) or UUID text file for firehose signpost log entries (chunks) + pub fn get_firehose_signpost<'a>( + firehose: &FirehoseSignpost, + strings_data: &'a [UUIDText], + shared_strings: &'a [SharedCacheStrings], + string_offset: u64, + first_proc_id: &u64, + second_proc_id: &u32, + catalogs: &CatalogChunk, + ) -> nom::IResult<&'a [u8], MessageData> { + if firehose.firehose_formatters.shared_cache + || (firehose.firehose_formatters.large_shared_cache != 0 + && firehose.firehose_formatters.has_large_offset != 0) + { + if firehose.firehose_formatters.has_large_offset != 0 { + let mut large_offset = firehose.firehose_formatters.has_large_offset; + // large_shared_cache should be double the value of has_large_offset + // Ex: has_large_offset = 1, large_shared_cache = 2 + // If the value do not match then there is an issue with shared string offset + // Can recover by using large_shared_cache + // Apple records this as an error: "error: ~~> " + // But is still able to get string formatter + if large_offset != firehose.firehose_formatters.large_shared_cache / 2 + && !firehose.firehose_formatters.shared_cache + { + large_offset = firehose.firehose_formatters.large_shared_cache / 2; + } + + // Large offset is 8 if shared_cache flag is set + if firehose.firehose_formatters.shared_cache { + large_offset = 8; + } + + // Combine large offset value with current string offset to get the true offset + let extra_offset_value = format!("{:X}{:07X}", large_offset, string_offset); + let extra_offset_value_result = u64::from_str_radix(&extra_offset_value, 16); + match extra_offset_value_result { + Ok(offset) => { + return MessageData::extract_shared_strings( + shared_strings, + strings_data, + offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + Err(err) => { + // We should not get errors since we are combining two numbers to create the offset + error!( + "Failed to get shared string offset to format string for signpost firehose entry: {:?}", + err + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + } + MessageData::extract_shared_strings( + shared_strings, + strings_data, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ) + } else { + if firehose.firehose_formatters.absolute { + let extra_offset_value = format!( + "{:X}{:08X}", + firehose.firehose_formatters.main_exe_alt_index, firehose.unknown_pc_id, + ); + + let offset_result = u64::from_str_radix(&extra_offset_value, 16); + match offset_result { + Ok(offset) => { + return MessageData::extract_absolute_strings( + strings_data, + offset, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + Err(err) => { + // We should not get errors since we are combining two numbers to create the offset + error!("Failed to get absolute offset to format string for signpost firehose entry: {:?}", err); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + } + if !firehose.firehose_formatters.uuid_relative.is_empty() { + return MessageData::extract_alt_uuid_strings( + strings_data, + string_offset, + &firehose.firehose_formatters.uuid_relative, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ); + } + MessageData::extract_format_strings( + strings_data, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + firehose.firehose_formatters.has_large_offset, + ) + } + } +} + +#[cfg(test)] +mod tests { + use crate::chunks::firehose::signpost::FirehoseSignpost; + use crate::parser::{collect_shared_strings, collect_strings, parse_log}; + use std::path::PathBuf; + + #[test] + fn test_parse_signpost() { + let test_data = [ + 225, 244, 2, 0, 1, 0, 238, 238, 178, 178, 181, 176, 238, 238, 176, 63, 27, 0, 0, 0, + ]; + let test_flags = 33282; + let (_, results) = FirehoseSignpost::parse_signpost(&test_data, &test_flags).unwrap(); + assert_eq!(results.unknown_pc_id, 193761); + assert_eq!(results.unknown_activity_id, 0); + assert_eq!(results.unknown_sentinel, 0); + assert_eq!(results.subsystem, 1); + assert_eq!(results.signpost_id, 17216892719917625070); + assert_eq!(results.signpost_name, 1785776); + assert_eq!(results.ttl_value, 0); + assert_eq!(results.data_ref_value, 0); + + assert_eq!(results.firehose_formatters.main_exe, true); + assert_eq!(results.firehose_formatters.shared_cache, false); + assert_eq!(results.firehose_formatters.has_large_offset, 0); + assert_eq!(results.firehose_formatters.large_shared_cache, 0); + assert_eq!(results.firehose_formatters.absolute, false); + assert_eq!(results.firehose_formatters.uuid_relative, String::new()); + assert_eq!(results.firehose_formatters.main_plugin, false); + assert_eq!(results.firehose_formatters.pc_style, false); + assert_eq!(results.firehose_formatters.main_exe_alt_index, 0); + } + + #[test] + fn test_get_firehose_signpost_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Signpost/0000000000000001.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let activity_type = 0x6; + + for catalog_data in log_data.catalog_data { + for preamble in catalog_data.firehose { + for firehose in preamble.public_data { + if firehose.unknown_log_activity_type == activity_type { + let (_, message_data) = FirehoseSignpost::get_firehose_signpost( + &firehose.firehose_signpost, + &string_results, + &shared_strings_results, + firehose.format_string_location as u64, + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ) + .unwrap(); + assert_eq!(message_data.format_string, ""); + assert_eq!(message_data.library, "/usr/libexec/kernelmanagerd"); + assert_eq!(message_data.process, "/usr/libexec/kernelmanagerd"); + assert_eq!( + message_data.process_uuid, + "CCCF30257483376883C824222233386D" + ); + assert_eq!( + message_data.library_uuid, + "CCCF30257483376883C824222233386D" + ); + + return; + } + } + } + } + } +} diff --git a/src/chunks/firehose/trace.rs b/src/chunks/firehose/trace.rs new file mode 100755 index 0000000..c3df073 --- /dev/null +++ b/src/chunks/firehose/trace.rs @@ -0,0 +1,162 @@ +use nom::bytes::complete::take; +use nom::number::complete::{le_u16, le_u32}; +use std::mem::size_of; + +use crate::catalog::CatalogChunk; +use crate::chunks::firehose::firehose_log::{FirehoseItemData, FirehoseItemInfo}; +use crate::chunks::firehose::message::MessageData; +use crate::uuidtext::UUIDText; + +#[derive(Debug, Clone)] +pub struct FirehoseTrace { + pub unknown_pc_id: u32, // Appears to be used to calculate string offset for firehose events with Absolute flag + pub message_value: u16, + pub unknown_data: Vec, +} + +impl FirehoseTrace { + /// Parse Trace Firehose log entry. + // Ex: tp 504 + 34: trace default (main_exe) + pub fn parse_firehose_trace(data: &[u8]) -> nom::IResult<&[u8], FirehoseTrace> { + let mut firehose_trace = FirehoseTrace { + unknown_pc_id: 0, + message_value: 0, + unknown_data: Vec::new(), + }; + let (input, unknown_pc_id) = take(size_of::())(data)?; + + // Trace logs only have message values if more than 4 bytes remaining in log entry + let minimum_message_size = 4; + if input.len() < minimum_message_size { + let (_, firehose_unknown_pc_id) = le_u32(unknown_pc_id)?; + firehose_trace.unknown_pc_id = firehose_unknown_pc_id; + let (input, unknown_data) = take(input.len())(input)?; + firehose_trace.unknown_data = unknown_data.to_vec(); + + return Ok((input, firehose_trace)); + } + let (input, message_value) = take(size_of::())(input)?; + let (input, unknown_data) = take(input.len())(input)?; + + let (_, firehose_unknown_pc_id) = le_u32(unknown_pc_id)?; + let (_, fireshose_message_value) = le_u16(message_value)?; + + firehose_trace.unknown_pc_id = firehose_unknown_pc_id; + // The rest of the trace log entry appears to be related to log message values + // But the data is stored differently from other log entries + // The data appears to be stored backwards? Ex: Data value, Data size, number of data entries, instead normal: number of data entries, data size, data value + firehose_trace.message_value = fireshose_message_value; + firehose_trace.unknown_data = unknown_data.to_vec(); + + Ok((input, firehose_trace)) + } + + /// Format the trace message data to make consistent with other log entries + pub fn get_trace_message_string(message: u16) -> FirehoseItemData { + let mut item_data = FirehoseItemData { + item_info: Vec::new(), + backtrace_strings: Vec::new(), + }; + + let item_info = FirehoseItemInfo { + message_strings: format!("{}", message), + item_type: 0, + item_size: 0, + }; + + item_data.item_info.push(item_info); + item_data + } + + /// Get base log message string formatter from shared cache strings (dsc) or UUID text file for firehose trace log entries (chunks) + pub fn get_firehose_trace_strings<'a>( + strings_data: &'a [UUIDText], + string_offset: u64, + first_proc_id: &u64, + second_proc_id: &u32, + catalogs: &CatalogChunk, + ) -> nom::IResult<&'a [u8], MessageData> { + // Only main_exe flag has been seen for format strings + MessageData::extract_format_strings( + strings_data, + string_offset, + first_proc_id, + second_proc_id, + catalogs, + 0, + ) + } +} + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use crate::{ + chunks::firehose::trace::FirehoseTrace, + parser::{collect_strings, parse_log}, + }; + + #[test] + fn test_parse_firehose_trace() { + let test_data = [106, 139, 3, 0, 0]; + let (_, results) = FirehoseTrace::parse_firehose_trace(&test_data).unwrap(); + assert_eq!(results.unknown_pc_id, 232298); + assert_eq!(results.message_value, 0); + assert_eq!(results.unknown_data.len(), 1); + + let test_data = [248, 145, 3, 0, 200, 0, 0, 0, 0, 0, 0, 0, 8, 1]; + let (_, results) = FirehoseTrace::parse_firehose_trace(&test_data).unwrap(); + assert_eq!(results.unknown_pc_id, 233976); + assert_eq!(results.message_value, 200); + assert_eq!(results.unknown_data.len(), 8); + } + + #[test] + fn test_get_trace_message_string() { + let test_message = 0; + let results = FirehoseTrace::get_trace_message_string(test_message); + assert_eq!(results.item_info[0].message_strings, "0"); + } + + #[test] + fn test_get_firehose_trace_strings() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_high_sierra.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("logdata.LiveData.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let activity_type = 0x3; + + for catalog_data in log_data.catalog_data { + for preamble in catalog_data.firehose { + for firehose in preamble.public_data { + if firehose.unknown_log_activity_type == activity_type { + let (_, message_data) = FirehoseTrace::get_firehose_trace_strings( + &string_results, + firehose.format_string_location as u64, + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ) + .unwrap(); + assert_eq!(message_data.format_string, "starting metadata download"); + assert_eq!(message_data.library, "/usr/libexec/mobileassetd"); + assert_eq!(message_data.process, "/usr/libexec/mobileassetd"); + assert_eq!( + message_data.process_uuid, + "CC6C867B44D63D0ABAA7598659629484" + ); + assert_eq!( + message_data.library_uuid, + "CC6C867B44D63D0ABAA7598659629484" + ); + return; + } + } + } + } + } +} diff --git a/src/chunks/mod.rs b/src/chunks/mod.rs new file mode 100644 index 0000000..7c24526 --- /dev/null +++ b/src/chunks/mod.rs @@ -0,0 +1,11 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +pub mod firehose; +pub mod oversize; +pub mod simpledump; +pub mod statedump; diff --git a/src/chunks/oversize.rs b/src/chunks/oversize.rs new file mode 100755 index 0000000..6962c02 --- /dev/null +++ b/src/chunks/oversize.rs @@ -0,0 +1,410 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use crate::chunks::firehose::firehose_log::{FirehoseItemData, FirehoseItemInfo, FirehosePreamble}; +use log::{info, warn}; +use nom::bytes::complete::take; +use nom::number::complete::{le_u16, le_u32, le_u64, le_u8}; +use std::mem::size_of; + +#[derive(Debug, Clone)] +pub struct Oversize { + pub chunk_tag: u32, + pub chunk_subtag: u32, + pub chunk_data_size: u64, + pub first_proc_id: u64, + pub second_proc_id: u32, + pub ttl: u8, + pub unknown_reserved: Vec, // 3 bytes + pub continuous_time: u64, + pub data_ref_index: u32, + pub public_data_size: u16, + pub private_data_size: u16, + pub message_items: FirehoseItemData, +} + +impl Oversize { + /// Parse the oversize log entry. Oversize entries contain strings that are too large to fit in a normal Firehose log entry + pub fn parse_oversize(data: &[u8]) -> nom::IResult<&[u8], Oversize> { + let mut oversize_results = Oversize { + chunk_tag: 0, + chunk_subtag: 0, + chunk_data_size: 0, + first_proc_id: 0, + second_proc_id: 0, + ttl: 0, + unknown_reserved: Vec::new(), + continuous_time: 0, + data_ref_index: 0, + public_data_size: 0, + private_data_size: 0, + message_items: FirehoseItemData { + item_info: Vec::new(), + backtrace_strings: Vec::new(), + }, + }; + + let (input, chunk_tag) = take(size_of::())(data)?; + let (input, chunk_sub_tag) = take(size_of::())(input)?; + let (input, chunk_data_size) = take(size_of::())(input)?; + let (input, first_number_proc_id) = take(size_of::())(input)?; + let (input, second_number_proc_id) = take(size_of::())(input)?; + + let (input, ttl) = take(size_of::())(input)?; + let unknown_reserved_size: u8 = 3; + let (input, unknown_reserved) = take(unknown_reserved_size)(input)?; + let (input, continuous_time) = take(size_of::())(input)?; + let (input, data_ref_index) = take(size_of::())(input)?; + let (input, public_data_size) = take(size_of::())(input)?; + let (input, private_data_size) = take(size_of::())(input)?; + + let (_, oversize_chunk_tag) = le_u32(chunk_tag)?; + let (_, oversize_chunk_sub_tag) = le_u32(chunk_sub_tag)?; + let (_, oversize_chunk_data_size) = le_u64(chunk_data_size)?; + let (_, oversize_first_proc_id) = le_u64(first_number_proc_id)?; + let (_, oversize_second_proc_id) = le_u32(second_number_proc_id)?; + + let (_, oversize_ttl) = le_u8(ttl)?; + let (_, oversize_continous_time) = le_u64(continuous_time)?; + let (_, oversize_data_ref_index) = le_u32(data_ref_index)?; + let (_, oversize_public_data_size) = le_u16(public_data_size)?; + let (_, oversize_private_data_size) = le_u16(private_data_size)?; + + oversize_results.chunk_tag = oversize_chunk_tag; + oversize_results.chunk_subtag = oversize_chunk_sub_tag; + oversize_results.chunk_data_size = oversize_chunk_data_size; + oversize_results.first_proc_id = oversize_first_proc_id; + oversize_results.second_proc_id = oversize_second_proc_id; + oversize_results.ttl = oversize_ttl; + oversize_results.continuous_time = oversize_continous_time; + oversize_results.data_ref_index = oversize_data_ref_index; + oversize_results.public_data_size = oversize_public_data_size; + oversize_results.private_data_size = oversize_private_data_size; + oversize_results.unknown_reserved = unknown_reserved.to_vec(); + + let mut oversize_data_size = + (oversize_results.public_data_size + oversize_results.private_data_size) as usize; + + // Contains item data like firehose (ex: 0x42) + if oversize_data_size > input.len() { + warn!("[macos-unifiedlogs] Oversize data size greater than Oversize remaining string size. Using remaining string size"); + oversize_data_size = input.len(); + } + let (input, pub_data) = take(oversize_data_size)(input)?; + + let (message_data, _) = take(size_of::())(pub_data)?; + let (message_data, item_count) = take(size_of::())(message_data)?; + let (_, oversize_item_count) = le_u8(item_count)?; + + let empty_flags = 0; + // Grab all message items from oversize data + let (oversize_private_data, mut firehose_item_data) = + FirehosePreamble::collect_items(message_data, &oversize_item_count, &empty_flags)?; + let (_, _) = + FirehosePreamble::parse_private_data(oversize_private_data, &mut firehose_item_data)?; + oversize_results.message_items = firehose_item_data; + Ok((input, oversize_results)) + } + + /// Function to get the firehose item info from the oversize log entry based on oversize (data ref) id, first proc id, and second proc id + pub fn get_oversize_strings( + data_ref: u32, + first_proc_id: u64, + second_proc_id: u32, + oversize_data: &Vec, + ) -> Vec { + let mut message_strings: Vec = Vec::new(); + + for oversize in oversize_data { + if data_ref == oversize.data_ref_index + && first_proc_id == oversize.first_proc_id + && second_proc_id == oversize.second_proc_id + { + for message in &oversize.message_items.item_info { + let oversize_firehose = FirehoseItemInfo { + message_strings: message.message_strings.to_owned(), + item_type: message.item_type, + item_size: message.item_size, + }; + message_strings.push(oversize_firehose); + } + return message_strings; + } + } + // We may not find any oversize data (data may have rolled from logs?) + info!("Did not find any oversize log entries from Data Ref ID: {}, First Proc ID: {}, and Second Proc ID: {}", data_ref, first_proc_id, second_proc_id); + message_strings + } +} + +#[cfg(test)] +mod tests { + use std::fs; + use std::path::PathBuf; + + use crate::chunks::firehose::firehose_log::{FirehoseItemData, FirehoseItemInfo}; + use crate::chunks::oversize::Oversize; + + #[test] + fn test_parse_oversize() { + let test_data = [ + 2, 96, 0, 0, 0, 0, 0, 0, 26, 13, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 193, 0, 0, + 0, 14, 0, 0, 0, 15, 132, 249, 225, 2, 0, 0, 0, 1, 0, 0, 0, 250, 12, 0, 0, 2, 1, 34, 4, + 0, 0, 242, 12, 83, 97, 110, 100, 98, 111, 120, 58, 32, 100, 105, 115, 107, 97, 114, 98, + 105, 116, 114, 97, 116, 105, 111, 110, 100, 40, 54, 51, 41, 32, 83, 121, 115, 116, 101, + 109, 32, 80, 111, 108, 105, 99, 121, 58, 32, 100, 101, 110, 121, 40, 53, 41, 32, 102, + 105, 108, 101, 45, 114, 101, 97, 100, 45, 109, 101, 116, 97, 100, 97, 116, 97, 32, 47, + 86, 111, 108, 117, 109, 101, 115, 47, 86, 77, 119, 97, 114, 101, 32, 83, 104, 97, 114, + 101, 100, 32, 70, 111, 108, 100, 101, 114, 115, 10, 86, 105, 111, 108, 97, 116, 105, + 111, 110, 58, 32, 32, 32, 32, 32, 32, 32, 83, 121, 115, 116, 101, 109, 32, 80, 111, + 108, 105, 99, 121, 58, 32, 100, 101, 110, 121, 40, 53, 41, 32, 102, 105, 108, 101, 45, + 114, 101, 97, 100, 45, 109, 101, 116, 97, 100, 97, 116, 97, 32, 47, 86, 111, 108, 117, + 109, 101, 115, 47, 86, 77, 119, 97, 114, 101, 32, 83, 104, 97, 114, 101, 100, 32, 70, + 111, 108, 100, 101, 114, 115, 32, 10, 80, 114, 111, 99, 101, 115, 115, 58, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, 116, 105, + 111, 110, 100, 32, 91, 54, 51, 93, 10, 80, 97, 116, 104, 58, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 47, 117, 115, 114, 47, 108, 105, 98, 101, 120, 101, 99, 47, + 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, 116, 105, 111, 110, 100, 10, 76, + 111, 97, 100, 32, 65, 100, 100, 114, 101, 115, 115, 58, 32, 32, 32, 32, 48, 120, 49, + 48, 55, 98, 57, 52, 48, 48, 48, 10, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, + 58, 32, 32, 32, 32, 32, 32, 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, 116, + 105, 111, 110, 100, 10, 86, 101, 114, 115, 105, 111, 110, 58, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 63, 63, 63, 32, 40, 63, 63, 63, 41, 10, 67, 111, 100, 101, 32, 84, 121, + 112, 101, 58, 32, 32, 32, 32, 32, 32, 32, 120, 56, 54, 95, 54, 52, 32, 40, 78, 97, 116, + 105, 118, 101, 41, 10, 80, 97, 114, 101, 110, 116, 32, 80, 114, 111, 99, 101, 115, 115, + 58, 32, 32, 108, 97, 117, 110, 99, 104, 100, 32, 91, 49, 93, 10, 82, 101, 115, 112, + 111, 110, 115, 105, 98, 108, 101, 58, 32, 32, 32, 32, 32, 47, 117, 115, 114, 47, 108, + 105, 98, 101, 120, 101, 99, 47, 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, + 116, 105, 111, 110, 100, 32, 91, 54, 51, 93, 10, 85, 115, 101, 114, 32, 73, 68, 58, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 48, 10, 10, 68, 97, 116, 101, 47, 84, 105, 109, 101, + 58, 32, 32, 32, 32, 32, 32, 32, 50, 48, 50, 49, 45, 48, 56, 45, 49, 55, 32, 49, 57, 58, + 53, 56, 58, 52, 57, 46, 57, 53, 53, 32, 69, 68, 84, 10, 79, 83, 32, 86, 101, 114, 115, + 105, 111, 110, 58, 32, 32, 32, 32, 32, 32, 77, 97, 99, 32, 79, 83, 32, 88, 32, 49, 48, + 46, 49, 51, 46, 54, 32, 40, 49, 55, 71, 54, 54, 41, 10, 82, 101, 112, 111, 114, 116, + 32, 86, 101, 114, 115, 105, 111, 110, 58, 32, 32, 56, 10, 10, 10, 77, 101, 116, 97, 68, + 97, 116, 97, 58, 32, 123, 34, 101, 114, 114, 110, 111, 34, 58, 53, 44, 34, 112, 114, + 111, 102, 105, 108, 101, 45, 102, 108, 97, 103, 115, 34, 58, 48, 44, 34, 116, 97, 114, + 103, 101, 116, 34, 58, 34, 92, 47, 86, 111, 108, 117, 109, 101, 115, 92, 47, 86, 77, + 119, 97, 114, 101, 32, 83, 104, 97, 114, 101, 100, 32, 70, 111, 108, 100, 101, 114, + 115, 34, 44, 34, 112, 114, 111, 99, 101, 115, 115, 34, 58, 34, 100, 105, 115, 107, 97, + 114, 98, 105, 116, 114, 97, 116, 105, 111, 110, 100, 34, 44, 34, 112, 97, 116, 104, 34, + 58, 34, 92, 47, 86, 111, 108, 117, 109, 101, 115, 92, 47, 86, 77, 119, 97, 114, 101, + 32, 83, 104, 97, 114, 101, 100, 32, 70, 111, 108, 100, 101, 114, 115, 34, 44, 34, 112, + 114, 105, 109, 97, 114, 121, 45, 102, 105, 108, 116, 101, 114, 34, 58, 34, 112, 97, + 116, 104, 34, 44, 34, 110, 111, 114, 109, 97, 108, 105, 122, 101, 100, 95, 116, 97, + 114, 103, 101, 116, 34, 58, 91, 34, 86, 111, 108, 117, 109, 101, 115, 34, 44, 34, 86, + 77, 119, 97, 114, 101, 32, 83, 104, 97, 114, 101, 100, 32, 70, 111, 108, 100, 101, 114, + 115, 34, 93, 44, 34, 112, 108, 97, 116, 102, 111, 114, 109, 45, 112, 111, 108, 105, 99, + 121, 34, 58, 116, 114, 117, 101, 44, 34, 115, 117, 109, 109, 97, 114, 121, 34, 58, 34, + 100, 101, 110, 121, 40, 53, 41, 32, 102, 105, 108, 101, 45, 114, 101, 97, 100, 45, 109, + 101, 116, 97, 100, 97, 116, 97, 32, 92, 47, 86, 111, 108, 117, 109, 101, 115, 92, 47, + 86, 77, 119, 97, 114, 101, 32, 83, 104, 97, 114, 101, 100, 32, 70, 111, 108, 100, 101, + 114, 115, 34, 44, 34, 112, 108, 97, 116, 102, 111, 114, 109, 95, 98, 105, 110, 97, 114, + 121, 34, 58, 34, 121, 101, 115, 34, 44, 34, 111, 112, 101, 114, 97, 116, 105, 111, 110, + 34, 58, 34, 102, 105, 108, 101, 45, 114, 101, 97, 100, 45, 109, 101, 116, 97, 100, 97, + 116, 97, 34, 44, 34, 112, 114, 105, 109, 97, 114, 121, 45, 102, 105, 108, 116, 101, + 114, 45, 118, 97, 108, 117, 101, 34, 58, 34, 92, 47, 86, 111, 108, 117, 109, 101, 115, + 92, 47, 86, 77, 119, 97, 114, 101, 32, 83, 104, 97, 114, 101, 100, 32, 70, 111, 108, + 100, 101, 114, 115, 34, 44, 34, 117, 105, 100, 34, 58, 48, 44, 34, 104, 97, 114, 100, + 119, 97, 114, 101, 34, 58, 34, 77, 97, 99, 34, 44, 34, 102, 108, 97, 103, 115, 34, 58, + 53, 44, 34, 112, 114, 111, 99, 101, 115, 115, 45, 112, 97, 116, 104, 34, 58, 34, 92, + 47, 117, 115, 114, 92, 47, 108, 105, 98, 101, 120, 101, 99, 92, 47, 100, 105, 115, 107, + 97, 114, 98, 105, 116, 114, 97, 116, 105, 111, 110, 100, 34, 44, 34, 112, 105, 100, 34, + 58, 54, 51, 44, 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 34, 112, 108, 97, 116, + 102, 111, 114, 109, 34, 44, 34, 98, 117, 105, 108, 100, 34, 58, 34, 77, 97, 99, 32, 79, + 83, 32, 88, 32, 49, 48, 46, 49, 51, 46, 54, 32, 40, 49, 55, 71, 54, 54, 41, 34, 44, 34, + 115, 105, 103, 110, 105, 110, 103, 45, 105, 100, 34, 58, 34, 99, 111, 109, 46, 97, 112, + 112, 108, 101, 46, 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, 116, 105, 111, + 110, 100, 34, 44, 34, 97, 99, 116, 105, 111, 110, 34, 58, 34, 100, 101, 110, 121, 34, + 44, 34, 112, 108, 97, 116, 102, 111, 114, 109, 45, 98, 105, 110, 97, 114, 121, 34, 58, + 116, 114, 117, 101, 125, 10, 10, 84, 104, 114, 101, 97, 100, 32, 48, 32, 40, 105, 100, + 58, 32, 53, 52, 50, 41, 58, 10, 48, 32, 32, 32, 108, 105, 98, 115, 121, 115, 116, 101, + 109, 95, 107, 101, 114, 110, 101, 108, 46, 100, 121, 108, 105, 98, 32, 32, 32, 32, 32, + 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, 102, 102, 54, 57, 51, 98, 98, 50, 51, + 54, 32, 95, 95, 103, 101, 116, 97, 116, 116, 114, 108, 105, 115, 116, 32, 43, 32, 49, + 48, 10, 49, 32, 32, 32, 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, 116, 105, + 111, 110, 100, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, + 48, 48, 48, 48, 48, 48, 49, 48, 55, 98, 57, 55, 100, 52, 54, 10, 50, 32, 32, 32, 100, + 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, 116, 105, 111, 110, 100, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 48, 48, 48, 49, 48, + 55, 98, 97, 51, 49, 54, 48, 10, 51, 32, 32, 32, 67, 111, 114, 101, 70, 111, 117, 110, + 100, 97, 116, 105, 111, 110, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, 102, 102, 52, 49, 52, 51, 98, 53, 54, 98, + 32, 95, 95, 67, 70, 77, 97, 99, 104, 80, 111, 114, 116, 80, 101, 114, 102, 111, 114, + 109, 32, 43, 32, 51, 52, 55, 10, 52, 32, 32, 32, 67, 111, 114, 101, 70, 111, 117, 110, + 100, 97, 116, 105, 111, 110, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, 102, 102, 52, 49, 52, 51, 98, 51, 102, 57, + 32, 95, 95, 67, 70, 82, 85, 78, 76, 79, 79, 80, 95, 73, 83, 95, 67, 65, 76, 76, 73, 78, + 71, 95, 79, 85, 84, 95, 84, 79, 95, 65, 95, 83, 79, 85, 82, 67, 69, 49, 95, 80, 69, 82, + 70, 79, 82, 77, 95, 70, 85, 78, 67, 84, 73, 79, 78, 95, 95, 32, 43, 32, 52, 49, 10, 53, + 32, 32, 32, 67, 111, 114, 101, 70, 111, 117, 110, 100, 97, 116, 105, 111, 110, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, + 102, 102, 102, 52, 49, 52, 51, 98, 51, 52, 53, 32, 95, 95, 67, 70, 82, 117, 110, 76, + 111, 111, 112, 68, 111, 83, 111, 117, 114, 99, 101, 49, 32, 43, 32, 53, 51, 51, 10, 54, + 32, 32, 32, 67, 111, 114, 101, 70, 111, 117, 110, 100, 97, 116, 105, 111, 110, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, + 102, 102, 102, 52, 49, 52, 51, 50, 102, 48, 48, 32, 95, 95, 67, 70, 82, 117, 110, 76, + 111, 111, 112, 82, 117, 110, 32, 43, 32, 50, 56, 52, 56, 10, 55, 32, 32, 32, 67, 111, + 114, 101, 70, 111, 117, 110, 100, 97, 116, 105, 111, 110, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, 102, 102, 52, + 49, 52, 51, 50, 49, 53, 51, 32, 67, 70, 82, 117, 110, 76, 111, 111, 112, 82, 117, 110, + 83, 112, 101, 99, 105, 102, 105, 99, 32, 43, 32, 52, 56, 51, 10, 56, 32, 32, 32, 67, + 111, 114, 101, 70, 111, 117, 110, 100, 97, 116, 105, 111, 110, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, 102, 102, + 52, 49, 52, 55, 48, 98, 101, 51, 32, 67, 70, 82, 117, 110, 76, 111, 111, 112, 82, 117, + 110, 32, 43, 32, 57, 57, 10, 57, 32, 32, 32, 100, 105, 115, 107, 97, 114, 98, 105, 116, + 114, 97, 116, 105, 111, 110, 100, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 9, 48, 120, 48, 48, 48, 48, 48, 48, 48, 49, 48, 55, 98, 57, 97, 99, 98, 54, 10, 49, + 48, 32, 32, 108, 105, 98, 100, 121, 108, 100, 46, 100, 121, 108, 105, 98, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, + 102, 102, 102, 54, 57, 50, 54, 98, 48, 49, 53, 32, 115, 116, 97, 114, 116, 32, 43, 32, + 49, 10, 49, 49, 32, 32, 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, 116, 105, + 111, 110, 100, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 10, 10, 84, 104, 114, 101, + 97, 100, 32, 49, 32, 40, 105, 100, 58, 32, 54, 56, 55, 41, 58, 10, 48, 32, 32, 32, 108, + 105, 98, 115, 121, 115, 116, 101, 109, 95, 107, 101, 114, 110, 101, 108, 46, 100, 121, + 108, 105, 98, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, 102, + 102, 54, 57, 51, 98, 99, 50, 56, 97, 32, 95, 95, 119, 111, 114, 107, 113, 95, 107, 101, + 114, 110, 114, 101, 116, 117, 114, 110, 32, 43, 32, 49, 48, 10, 49, 32, 32, 32, 108, + 105, 98, 115, 121, 115, 116, 101, 109, 95, 112, 116, 104, 114, 101, 97, 100, 46, 100, + 121, 108, 105, 98, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, + 102, 102, 54, 57, 53, 56, 50, 98, 101, 57, 32, 115, 116, 97, 114, 116, 95, 119, 113, + 116, 104, 114, 101, 97, 100, 32, 43, 32, 49, 51, 10, 10, 84, 104, 114, 101, 97, 100, + 32, 50, 32, 40, 105, 100, 58, 32, 49, 53, 52, 49, 41, 58, 10, 48, 32, 32, 32, 108, 105, + 98, 115, 121, 115, 116, 101, 109, 95, 107, 101, 114, 110, 101, 108, 46, 100, 121, 108, + 105, 98, 32, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, 102, 102, + 54, 57, 51, 98, 99, 50, 56, 97, 32, 95, 95, 119, 111, 114, 107, 113, 95, 107, 101, 114, + 110, 114, 101, 116, 117, 114, 110, 32, 43, 32, 49, 48, 10, 49, 32, 32, 32, 108, 105, + 98, 115, 121, 115, 116, 101, 109, 95, 112, 116, 104, 114, 101, 97, 100, 46, 100, 121, + 108, 105, 98, 32, 32, 32, 32, 32, 32, 32, 9, 48, 120, 48, 48, 48, 48, 55, 102, 102, + 102, 54, 57, 53, 56, 50, 98, 101, 57, 32, 115, 116, 97, 114, 116, 95, 119, 113, 116, + 104, 114, 101, 97, 100, 32, 43, 32, 49, 51, 10, 10, 66, 105, 110, 97, 114, 121, 32, 73, + 109, 97, 103, 101, 115, 58, 10, 32, 32, 32, 32, 32, 32, 32, 48, 120, 49, 48, 55, 98, + 57, 52, 48, 48, 48, 32, 45, 32, 32, 32, 32, 32, 32, 32, 32, 48, 120, 49, 48, 55, 98, + 97, 98, 102, 102, 102, 32, 32, 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, 97, 116, + 105, 111, 110, 100, 32, 40, 50, 57, 55, 46, 55, 48, 46, 49, 41, 32, 60, 49, 57, 48, + 101, 102, 55, 51, 102, 45, 99, 50, 48, 52, 45, 51, 49, 98, 99, 45, 98, 100, 53, 49, 45, + 101, 49, 98, 101, 52, 100, 101, 97, 102, 57, 48, 97, 62, 32, 47, 117, 115, 114, 47, + 108, 105, 98, 101, 120, 101, 99, 47, 100, 105, 115, 107, 97, 114, 98, 105, 116, 114, + 97, 116, 105, 111, 110, 100, 10, 32, 32, 32, 32, 48, 120, 55, 102, 102, 102, 52, 49, + 51, 97, 100, 48, 48, 48, 32, 45, 32, 32, 32, 32, 32, 48, 120, 55, 102, 102, 102, 52, + 49, 56, 52, 101, 102, 101, 102, 32, 32, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, + 67, 111, 114, 101, 70, 111, 117, 110, 100, 97, 116, 105, 111, 110, 32, 40, 54, 46, 57, + 32, 45, 32, 49, 52, 53, 52, 46, 57, 48, 41, 32, 60, 101, 53, 100, 53, 57, 52, 98, 102, + 45, 57, 49, 52, 50, 45, 51, 51, 50, 53, 45, 97, 54, 50, 100, 45, 99, 102, 52, 97, 97, + 102, 52, 55, 50, 54, 52, 50, 62, 32, 47, 83, 121, 115, 116, 101, 109, 47, 76, 105, 98, + 114, 97, 114, 121, 47, 70, 114, 97, 109, 101, 119, 111, 114, 107, 115, 47, 67, 111, + 114, 101, 70, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 102, 114, 97, 109, 101, + 119, 111, 114, 107, 47, 86, 101, 114, 115, 105, 111, 110, 115, 47, 65, 47, 67, 111, + 114, 101, 70, 111, 117, 110, 100, 97, 116, 105, 111, 110, 10, 32, 32, 32, 32, 48, 120, + 55, 102, 102, 102, 54, 57, 50, 54, 97, 48, 48, 48, 32, 45, 32, 32, 32, 32, 32, 48, 120, + 55, 102, 102, 102, 54, 57, 50, 56, 55, 102, 102, 55, 32, 32, 108, 105, 98, 100, 121, + 108, 100, 46, 100, 121, 108, 105, 98, 32, 40, 53, 53, 49, 46, 52, 41, 32, 60, 56, 49, + 98, 102, 51, 97, 56, 50, 45, 53, 55, 49, 57, 45, 51, 98, 53, 52, 45, 97, 98, 97, 57, + 45, 55, 54, 99, 56, 50, 100, 57, 51, 50, 99, 97, 99, 62, 32, 47, 117, 115, 114, 47, + 108, 105, 98, 47, 115, 121, 115, 116, 101, 109, 47, 108, 105, 98, 100, 121, 108, 100, + 46, 100, 121, 108, 105, 98, 10, 32, 32, 32, 32, 48, 120, 55, 102, 102, 102, 54, 57, 51, + 57, 102, 48, 48, 48, 32, 45, 32, 32, 32, 32, 32, 48, 120, 55, 102, 102, 102, 54, 57, + 51, 99, 53, 102, 102, 55, 32, 32, 108, 105, 98, 115, 121, 115, 116, 101, 109, 95, 107, + 101, 114, 110, 101, 108, 46, 100, 121, 108, 105, 98, 32, 40, 52, 53, 55, 48, 46, 55, + 49, 46, 50, 41, 32, 60, 102, 50, 50, 98, 56, 100, 55, 51, 45, 54, 57, 100, 56, 45, 51, + 54, 100, 55, 45, 98, 102, 54, 54, 45, 55, 102, 57, 97, 99, 55, 48, 99, 48, 56, 99, 50, + 62, 32, 47, 117, 115, 114, 47, 108, 105, 98, 47, 115, 121, 115, 116, 101, 109, 47, 108, + 105, 98, 115, 121, 115, 116, 101, 109, 95, 107, 101, 114, 110, 101, 108, 46, 100, 121, + 108, 105, 98, 10, 32, 32, 32, 32, 48, 120, 55, 102, 102, 102, 54, 57, 53, 56, 48, 48, + 48, 48, 32, 45, 32, 32, 32, 32, 32, 48, 120, 55, 102, 102, 102, 54, 57, 53, 56, 98, + 102, 102, 102, 32, 32, 108, 105, 98, 115, 121, 115, 116, 101, 109, 95, 112, 116, 104, + 114, 101, 97, 100, 46, 100, 121, 108, 105, 98, 32, 40, 51, 48, 49, 46, 53, 48, 46, 49, + 41, 32, 60, 48, 101, 53, 49, 99, 99, 98, 97, 45, 57, 49, 102, 50, 45, 51, 52, 101, 49, + 45, 98, 102, 50, 97, 45, 102, 101, 101, 102, 100, 51, 100, 51, 50, 49, 101, 52, 62, 32, + 47, 117, 115, 114, 47, 108, 105, 98, 47, 115, 121, 115, 116, 101, 109, 47, 108, 105, + 98, 115, 121, 115, 116, 101, 109, 95, 112, 116, 104, 114, 101, 97, 100, 46, 100, 121, + 108, 105, 98, 10, 10, 10, 0, + ]; + let (_, oversize_results) = Oversize::parse_oversize(&test_data).unwrap(); + assert_eq!(oversize_results.chunk_tag, 0x6002); + assert_eq!(oversize_results.chunk_subtag, 0); + assert_eq!(oversize_results.chunk_data_size, 3354); + assert_eq!(oversize_results.first_proc_id, 192); + assert_eq!(oversize_results.second_proc_id, 193); + assert_eq!(oversize_results.ttl, 14); + assert_eq!(oversize_results.unknown_reserved, [0, 0, 0]); + assert_eq!(oversize_results.continuous_time, 12381160463); + assert_eq!(oversize_results.data_ref_index, 1); + assert_eq!(oversize_results.public_data_size, 3322); + assert_eq!(oversize_results.private_data_size, 0); + assert_eq!(oversize_results.message_items.item_info[0].message_strings, "Sandbox: diskarbitrationd(63) System Policy: deny(5) file-read-metadata /Volumes/VMware Shared Folders\nViolation: System Policy: deny(5) file-read-metadata /Volumes/VMware Shared Folders \nProcess: diskarbitrationd [63]\nPath: /usr/libexec/diskarbitrationd\nLoad Address: 0x107b94000\nIdentifier: diskarbitrationd\nVersion: ??? (???)\nCode Type: x86_64 (Native)\nParent Process: launchd [1]\nResponsible: /usr/libexec/diskarbitrationd [63]\nUser ID: 0\n\nDate/Time: 2021-08-17 19:58:49.955 EDT\nOS Version: Mac OS X 10.13.6 (17G66)\nReport Version: 8\n\n\nMetaData: {\"errno\":5,\"profile-flags\":0,\"target\":\"\\/Volumes\\/VMware Shared Folders\",\"process\":\"diskarbitrationd\",\"path\":\"\\/Volumes\\/VMware Shared Folders\",\"primary-filter\":\"path\",\"normalized_target\":[\"Volumes\",\"VMware Shared Folders\"],\"platform-policy\":true,\"summary\":\"deny(5) file-read-metadata \\/Volumes\\/VMware Shared Folders\",\"platform_binary\":\"yes\",\"operation\":\"file-read-metadata\",\"primary-filter-value\":\"\\/Volumes\\/VMware Shared Folders\",\"uid\":0,\"hardware\":\"Mac\",\"flags\":5,\"process-path\":\"\\/usr\\/libexec\\/diskarbitrationd\",\"pid\":63,\"profile\":\"platform\",\"build\":\"Mac OS X 10.13.6 (17G66)\",\"signing-id\":\"com.apple.diskarbitrationd\",\"action\":\"deny\",\"platform-binary\":true}\n\nThread 0 (id: 542):\n0 libsystem_kernel.dylib \t0x00007fff693bb236 __getattrlist + 10\n1 diskarbitrationd \t0x0000000107b97d46\n2 diskarbitrationd \t0x0000000107ba3160\n3 CoreFoundation \t0x00007fff4143b56b __CFMachPortPerform + 347\n4 CoreFoundation \t0x00007fff4143b3f9 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41\n5 CoreFoundation \t0x00007fff4143b345 __CFRunLoopDoSource1 + 533\n6 CoreFoundation \t0x00007fff41432f00 __CFRunLoopRun + 2848\n7 CoreFoundation \t0x00007fff41432153 CFRunLoopRunSpecific + 483\n8 CoreFoundation \t0x00007fff41470be3 CFRunLoopRun + 99\n9 diskarbitrationd \t0x0000000107b9acb6\n10 libdyld.dylib \t0x00007fff6926b015 start + 1\n11 diskarbitrationd \t0x0000000000000001\n\nThread 1 (id: 687):\n0 libsystem_kernel.dylib \t0x00007fff693bc28a __workq_kernreturn + 10\n1 libsystem_pthread.dylib \t0x00007fff69582be9 start_wqthread + 13\n\nThread 2 (id: 1541):\n0 libsystem_kernel.dylib \t0x00007fff693bc28a __workq_kernreturn + 10\n1 libsystem_pthread.dylib \t0x00007fff69582be9 start_wqthread + 13\n\nBinary Images:\n 0x107b94000 - 0x107babfff diskarbitrationd (297.70.1) <190ef73f-c204-31bc-bd51-e1be4deaf90a> /usr/libexec/diskarbitrationd\n 0x7fff413ad000 - 0x7fff4184efef com.apple.CoreFoundation (6.9 - 1454.90) /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation\n 0x7fff6926a000 - 0x7fff69287ff7 libdyld.dylib (551.4) <81bf3a82-5719-3b54-aba9-76c82d932cac> /usr/lib/system/libdyld.dylib\n 0x7fff6939f000 - 0x7fff693c5ff7 libsystem_kernel.dylib (4570.71.2) /usr/lib/system/libsystem_kernel.dylib\n 0x7fff69580000 - 0x7fff6958bfff libsystem_pthread.dylib (301.50.1) <0e51ccba-91f2-34e1-bf2a-feefd3d321e4> /usr/lib/system/libsystem_pthread.dylib\n\n\n"); + } + + #[test] + fn test_parse_oversize_private_strings() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Oversize Tests/oversize_private_strings.raw"); + let buffer = fs::read(test_path).unwrap(); + + let (_, oversize_results) = Oversize::parse_oversize(&buffer).unwrap(); + assert_eq!(oversize_results.chunk_tag, 0x6002); + assert_eq!(oversize_results.chunk_subtag, 0); + assert_eq!(oversize_results.chunk_data_size, 2963); + assert_eq!(oversize_results.first_proc_id, 86); + assert_eq!(oversize_results.second_proc_id, 302); + assert_eq!(oversize_results.ttl, 0); + assert_eq!(oversize_results.unknown_reserved, [0, 0, 0]); + assert_eq!(oversize_results.continuous_time, 96693842097); + assert_eq!(oversize_results.data_ref_index, 1); + assert_eq!(oversize_results.public_data_size, 8); + assert_eq!(oversize_results.private_data_size, 2923); + assert_eq!( + oversize_results.message_items.item_info[0].message_strings, + "updated queuedEvents[4]=(\n \"FudEvent - Client:(null) Type:114 Filter:com.apple.MobileAccessoryUpdater.EA.app.multiasset.A2015.59 Data: { count = 5, transaction: 0, voucher = 0x7fdac460e7c0, contents =\\n\\t\\\"Command\\\" => : 114\\n\\t\\\"PluginIdentifier\\\" => { length = 49, contents = \\\"com.apple.MobileAccessoryUpdater.EAUpdaterService\\\" }\\n\\t\\\"_State\\\" => : 0\\n\\t\\\"XPCEventName\\\" => { length = 59, contents = \\\"com.apple.MobileAccessoryUpdater.EA.app.multiasset.A2015.59\\\" }\\n\\t\\\"Notification\\\" => { length = 44, contents = \\\"com.apple.corespeech.voicetriggerassetchange\\\" }\\n} Options:{\\n}\",\n \"FudEvent - Client:(null) Type:114 Filter:com.apple.MobileAccessoryUpdater.EA.app.multiasset.A1881.58 Data: { count = 5, transaction: 0, voucher = 0x7fdac460e7c0, contents =\\n\\t\\\"Command\\\" => : 114\\n\\t\\\"PluginIdentifier\\\" => { length = 49, contents = \\\"com.apple.MobileAccessoryUpdater.EAUpdaterService\\\" }\\n\\t\\\"_State\\\" => : 0\\n\\t\\\"XPCEventName\\\" => { length = 59, contents = \\\"com.apple.MobileAccessoryUpdater.EA.app.multiasset.A1881.58\\\" }\\n\\t\\\"Notification\\\" => { length = 44, contents = \\\"com.apple.corespeech.voicetriggerassetchange\\\" }\\n} Options:{\\n}\",\n \"FudEvent - Client:(null) Type:114 Filter:com.apple.MobileAccessoryUpdater.EA.app.multiasset.A2048.57 Data: { count = 5, transaction: 0, voucher = 0x7fdac460e7c0, contents =\\n\\t\\\"Command\\\" => : 114\\n\\t\\\"PluginIdentifier\\\" => { length = 49, contents = \\\"com.apple.MobileAccessoryUpdater.EAUpdaterService\\\" }\\n\\t\\\"_State\\\" => : 0\\n\\t\\\"XPCEventName\\\" => { length = 59, contents = \\\"com.apple.MobileAccessoryUpdater.EA.app.multiasset.A2048.57\\\" }\\n\\t\\\"Notification\\\" => { length = 44, contents = \\\"com.apple.corespeech.voicetriggerassetchange\\\" }\\n} Options:{\\n}\",\n \"FudEvent - Client:(null) Type:114 Filter:com.apple.MobileAccessoryUpdater.EA.app.multiasset.A2032.61 Data: { count = 5, transaction: 0, voucher = 0x7fdac460e7c0, contents =\\n\\t\\\"Command\\\" => : 114\\n\\t\\\"PluginIdentifier\\\" => { length = 49, contents = \\\"com.apple.MobileAccessoryUpdater.EAUpdaterService\\\" }\\n\\t\\\"_State\\\" => : 0\\n\\t\\\"XPCEventName\\\" => { length = 59, contents = \\\"com.apple.MobileAccessoryUpdater.EA.app.multiasset.A2032.61\\\" }\\n\\t\\\"Notification\\\" => { length = 44, contents = \\\"com.apple.corespeech.voicetriggerassetchange\\\" }\\n} Options:{\\n}\"\n)" + ); + } + + #[test] + fn test_get_oversize_strings_big_sur() { + let data = vec![Oversize { + chunk_tag: 24578, + chunk_subtag: 0, + chunk_data_size: 1124, + first_proc_id: 96, + second_proc_id: 245, + ttl: 0, + unknown_reserved: Vec::new(), + continuous_time: 5609252490, + data_ref_index: 1, + public_data_size: 1092, + private_data_size: 0, + message_items: FirehoseItemData { + item_info: vec![ + FirehoseItemInfo { + message_strings: String::from("system kext collection"), + item_type: 34, + item_size: 0, + }, + FirehoseItemInfo { + message_strings: String::from( + "/System/Library/KernelCollections/SystemKernelExtensions.kc", + ), + item_type: 34, + item_size: 0, + }, + ], + backtrace_strings: Vec::new(), + }, + }]; + let data_ref = 1; + let first_proc_id = 96; + let second_proc_id = 245; + let results = + Oversize::get_oversize_strings(data_ref, first_proc_id, second_proc_id, &data); + assert_eq!(results[0].message_strings, "system kext collection"); + assert_eq!( + results[1].message_strings, + "/System/Library/KernelCollections/SystemKernelExtensions.kc" + ); + } +} diff --git a/src/chunks/simpledump.rs b/src/chunks/simpledump.rs new file mode 100755 index 0000000..38b403a --- /dev/null +++ b/src/chunks/simpledump.rs @@ -0,0 +1,173 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use crate::util::{clean_uuid, extract_string}; +use nom::bytes::complete::take; +use nom::number::complete::{le_u16, le_u32, le_u64}; +use std::mem::size_of; + +/* + Introduced in macOS Monterey (12). Appears to be a "simpler" version of Statedump? + So far appears to just contain a single string +*/ +#[derive(Debug, Clone)] +pub struct SimpleDump { + pub chunk_tag: u32, + pub chunk_subtag: u32, + pub chunk_data_size: u64, + pub first_proc_id: u64, + pub second_proc_id: u64, + pub continous_time: u64, + pub thread_id: u64, + pub unknown_offset: u32, + pub unknown_ttl: u16, + pub unknown_type: u16, + pub sender_uuid: String, + pub dsc_uuid: String, + pub unknown_number_message_strings: u32, + pub unknown_size_subsystem_string: u32, + pub unknown_size_message_string: u32, + pub subsystem: String, + pub message_string: String, +} + +impl SimpleDump { + /// Parse Simpledump log entry. Introduced in macOS Monterey (12) + pub fn parse_simpledump(data: &[u8]) -> nom::IResult<&[u8], SimpleDump> { + let mut simpledump_resuls = SimpleDump { + chunk_tag: 0, + chunk_subtag: 0, + chunk_data_size: 0, + first_proc_id: 0, + second_proc_id: 0, + continous_time: 0, + thread_id: 0, + unknown_offset: 0, + unknown_ttl: 0, + unknown_type: 0, + sender_uuid: String::new(), + dsc_uuid: String::new(), + unknown_number_message_strings: 0, + unknown_size_subsystem_string: 0, + unknown_size_message_string: 0, + subsystem: String::new(), + message_string: String::new(), + }; + let (input, chunk_tag) = take(size_of::())(data)?; + let (input, chunk_sub_tag) = take(size_of::())(input)?; + let (input, chunk_data_size) = take(size_of::())(input)?; + let (input, first_number_proc_id) = take(size_of::())(input)?; + let (input, second_number_proc_id) = take(size_of::())(input)?; + + let (input, continous_time) = take(size_of::())(input)?; + let (input, thread_id) = take(size_of::())(input)?; + let (input, unknown_offset) = take(size_of::())(input)?; + let (input, unknown_ttl) = take(size_of::())(input)?; + let (input, unknown_type) = take(size_of::())(input)?; + let (input, sender_uuid) = take(size_of::())(input)?; + let (input, dsc_uuid) = take(size_of::())(input)?; + let (input, unknown_number_message_strings) = take(size_of::())(input)?; + let (input, unknown_size_subsystem_string) = take(size_of::())(input)?; + let (input, unknown_size_message_string) = take(size_of::())(input)?; + + let (_, simpledump_chunk_tag) = le_u32(chunk_tag)?; + let (_, simpledump_chunk_sub_tag) = le_u32(chunk_sub_tag)?; + let (_, simpledump_chunk_data_size) = le_u64(chunk_data_size)?; + let (_, simpledump_first_proc_id) = le_u64(first_number_proc_id)?; + let (_, simpledump_second_proc_id) = le_u64(second_number_proc_id)?; + + let (_, simpledump_continous_time) = le_u64(continous_time)?; + let (_, simpledump_thread_id) = le_u64(thread_id)?; + let (_, simpledump_unknown_offset) = le_u32(unknown_offset)?; + let (_, simpledump_unknown_ttl) = le_u16(unknown_ttl)?; + let (_, simpledump_unknown_type) = le_u16(unknown_type)?; + let (_, simpledump_unknown_number_message_strings) = + le_u32(unknown_number_message_strings)?; + let (_, simpledump_unknown_size_subsystem_string) = le_u32(unknown_size_subsystem_string)?; + let (_, simpledump_unknown_size_message_string) = le_u32(unknown_size_message_string)?; + let sender_uuid_string = format!("{:02X?}", sender_uuid); + let dsc_uuid_string = format!("{:02X?}", dsc_uuid); + + simpledump_resuls.chunk_tag = simpledump_chunk_tag; + simpledump_resuls.chunk_subtag = simpledump_chunk_sub_tag; + simpledump_resuls.chunk_data_size = simpledump_chunk_data_size; + simpledump_resuls.continous_time = simpledump_continous_time; + simpledump_resuls.first_proc_id = simpledump_first_proc_id; + simpledump_resuls.second_proc_id = simpledump_second_proc_id; + simpledump_resuls.thread_id = simpledump_thread_id; + simpledump_resuls.unknown_offset = simpledump_unknown_offset; + simpledump_resuls.unknown_ttl = simpledump_unknown_ttl; + simpledump_resuls.unknown_type = simpledump_unknown_type; + + simpledump_resuls.sender_uuid = clean_uuid(&sender_uuid_string); + simpledump_resuls.dsc_uuid = clean_uuid(&dsc_uuid_string); + simpledump_resuls.unknown_number_message_strings = + simpledump_unknown_number_message_strings; + simpledump_resuls.unknown_size_subsystem_string = simpledump_unknown_size_subsystem_string; + simpledump_resuls.unknown_size_message_string = simpledump_unknown_size_message_string; + + let (input, subsystem_string) = take(simpledump_unknown_size_subsystem_string)(input)?; + let (input, message_string) = take(simpledump_unknown_size_message_string)(input)?; + + if !subsystem_string.is_empty() { + let (_, simpledump_subsystem_string) = extract_string(subsystem_string)?; + simpledump_resuls.subsystem = simpledump_subsystem_string; + } + if !message_string.is_empty() { + let (_, simpledump_message_string) = extract_string(message_string)?; + simpledump_resuls.message_string = simpledump_message_string; + } + Ok((input, simpledump_resuls)) + } +} + +#[cfg(test)] +mod tests { + use super::SimpleDump; + + #[test] + fn test_parse_simpledump() { + let test_data = [ + 4, 96, 0, 0, 0, 0, 0, 0, 219, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 45, 182, 196, 71, 133, 4, 0, 0, 3, 234, 0, 0, 0, 0, 0, 0, 118, 118, 1, 0, + 0, 0, 0, 0, 13, 207, 62, 139, 73, 35, 50, 62, 179, 229, 84, 115, 7, 207, 14, 172, 61, + 5, 132, 95, 63, 101, 53, 143, 158, 191, 34, 54, 231, 114, 172, 1, 1, 0, 0, 0, 79, 0, 0, + 0, 56, 0, 0, 0, 117, 115, 101, 114, 47, 53, 48, 49, 47, 99, 111, 109, 46, 97, 112, 112, + 108, 101, 46, 109, 100, 119, 111, 114, 107, 101, 114, 46, 115, 104, 97, 114, 101, 100, + 46, 48, 66, 48, 48, 48, 48, 48, 48, 45, 48, 48, 48, 48, 45, 48, 48, 48, 48, 45, 48, 48, + 48, 48, 45, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 91, 52, 50, 50, 57, 93, + 0, 115, 101, 114, 118, 105, 99, 101, 32, 101, 120, 105, 116, 101, 100, 58, 32, 100, + 105, 114, 116, 121, 32, 61, 32, 48, 44, 32, 115, 117, 112, 112, 111, 114, 116, 101, + 100, 32, 112, 114, 101, 115, 115, 117, 114, 101, 100, 45, 101, 120, 105, 116, 32, 61, + 32, 49, 0, 0, 0, 0, 0, 0, + ]; + let (_, results) = SimpleDump::parse_simpledump(&test_data).unwrap(); + assert_eq!(results.chunk_tag, 24580); // 0x6004 - simpledump chunk tag + assert_eq!(results.chunk_subtag, 0); + assert_eq!(results.chunk_data_size, 219); + assert_eq!(results.first_proc_id, 1); + assert_eq!(results.second_proc_id, 1); + assert_eq!(results.continous_time, 4970481235501); + assert_eq!(results.thread_id, 59907); + assert_eq!(results.unknown_offset, 95862); + assert_eq!(results.unknown_ttl, 0); + assert_eq!(results.unknown_type, 0); + assert_eq!(results.sender_uuid, "0DCF3E8B4923323EB3E5547307CF0EAC"); + assert_eq!(results.dsc_uuid, "3D05845F3F65358F9EBF2236E772AC01"); + assert_eq!(results.unknown_number_message_strings, 1); + assert_eq!(results.unknown_size_subsystem_string, 79); + assert_eq!(results.unknown_size_message_string, 56); + assert_eq!( + results.subsystem, + "user/501/com.apple.mdworker.shared.0B000000-0000-0000-0000-000000000000 [4229]" + ); + assert_eq!( + results.message_string, + "service exited: dirty = 0, supported pressured-exit = 1" + ); + } +} diff --git a/src/chunks/statedump.rs b/src/chunks/statedump.rs new file mode 100755 index 0000000..70d7dad --- /dev/null +++ b/src/chunks/statedump.rs @@ -0,0 +1,1033 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use crate::util::{clean_uuid, extract_string}; +use log::{error, info}; +use nom::bytes::complete::take; +use nom::number::complete::{le_u32, le_u64, le_u8}; +use plist::Value; +use std::mem::size_of; + +#[derive(Debug, Clone)] +pub struct Statedump { + pub chunk_tag: u32, + pub chunk_subtag: u32, + pub chunk_data_size: u64, + pub first_proc_id: u64, + pub second_proc_id: u32, + pub ttl: u8, + pub unknown_reserved: Vec, // 3 bytes + pub continuous_time: u64, + pub activity_id: u64, + pub uuid: String, + pub unknown_data_type: u32, // 1 = plist, 3 = custom object?, 2 = (protocol buffer?) + pub unknown_data_size: u32, // Size of statedump data + pub unknown_object_type_string_1: String, + pub unknown_object_type_string_2: String, + pub unknown_name: String, + pub statedump_data: Vec, +} + +impl Statedump { + /// Parse Statedump log entry. Statedumps are special log entries that may contain a plist file, custom object, or protocol buffer + pub fn parse_statedump(data: &[u8]) -> nom::IResult<&[u8], Statedump> { + let mut statedump_results = Statedump { + chunk_tag: 0, + chunk_subtag: 0, + chunk_data_size: 0, + first_proc_id: 0, + second_proc_id: 0, + ttl: 0, + unknown_reserved: Vec::new(), + continuous_time: 0, + activity_id: 0, + uuid: String::new(), + unknown_data_type: 0, + unknown_data_size: 0, + unknown_object_type_string_1: String::new(), + unknown_object_type_string_2: String::new(), + unknown_name: String::new(), + statedump_data: Vec::new(), + }; + let (input, chunk_tag) = take(size_of::())(data)?; + let (input, chunk_sub_tag) = take(size_of::())(input)?; + let (input, chunk_data_size) = take(size_of::())(input)?; + let (input, first_number_proc_id) = take(size_of::())(input)?; + let (input, second_number_proc_id) = take(size_of::())(input)?; + + let (input, ttl) = take(size_of::())(input)?; + let unknown_reserved_size: u8 = 3; + let (input, unknown_reserved) = take(unknown_reserved_size)(input)?; + let (input, continuous_time) = take(size_of::())(input)?; + let (input, activity_id) = take(size_of::())(input)?; + let (input, uuid) = take(size_of::())(input)?; + let (input, unknown_data_type) = take(size_of::())(input)?; + + let (_, statedump_chunk_tag) = le_u32(chunk_tag)?; + let (_, statedump_chunk_sub_tag) = le_u32(chunk_sub_tag)?; + let (_, statedump_chunk_data_size) = le_u64(chunk_data_size)?; + let (_, statedump_first_proc_id) = le_u64(first_number_proc_id)?; + let (_, statedump_second_proc_id) = le_u32(second_number_proc_id)?; + + let (_, statedump_ttl) = le_u8(ttl)?; + let (_, statedump_continous_time) = le_u64(continuous_time)?; + let (_, statedump_activity_id) = le_u64(activity_id)?; + let (_, statedump_unknown_data_type) = le_u32(unknown_data_type)?; + + let (input, unknown_data_size) = take(size_of::())(input)?; + let (_, statedump_unknown_data_size) = le_u32(unknown_data_size)?; + + let string_size: u8 = 64; + let (input, unknown_object_type_string_1) = take(string_size)(input)?; + let (input, unknown_object_type_string_2) = take(string_size)(input)?; + let (input, unknown_name) = take(string_size)(input)?; + + statedump_results.chunk_tag = statedump_chunk_tag; + statedump_results.chunk_subtag = statedump_chunk_sub_tag; + statedump_results.chunk_data_size = statedump_chunk_data_size; + statedump_results.first_proc_id = statedump_first_proc_id; + statedump_results.second_proc_id = statedump_second_proc_id; + statedump_results.ttl = statedump_ttl; + statedump_results.unknown_reserved = unknown_reserved.to_vec(); + statedump_results.continuous_time = statedump_continous_time; + statedump_results.activity_id = statedump_activity_id; + statedump_results.unknown_data_type = statedump_unknown_data_type; + statedump_results.unknown_data_size = statedump_unknown_data_size; + + let uuid_string = format!("{:02X?}", uuid); + statedump_results.uuid = clean_uuid(&uuid_string); + let (_, statedump_name) = extract_string(unknown_name)?; + statedump_results.unknown_name = statedump_name; + let (_, object_string_1) = extract_string(unknown_object_type_string_1)?; + let (_, object_string_2) = extract_string(unknown_object_type_string_2)?; + + statedump_results.unknown_object_type_string_1 = object_string_1; + statedump_results.unknown_object_type_string_2 = object_string_2; + let (input, statedump_data) = take(statedump_unknown_data_size)(input)?; + + statedump_results.statedump_data = statedump_data.to_vec(); + Ok((input, statedump_results)) + } + + /// Parse the binary plist file in the log. The plist may be empty + pub fn parse_statedump_plist(plist_data: &[u8]) -> String { + if plist_data.is_empty() { + info!("[macos-unifiedlogs] Empty plist data in statedump"); + return String::from("Empty plist data"); + } + let data: Result = plist::from_bytes(plist_data); + match data { + Ok(results) => { + let json_data = serde_json::to_string(&results); + match json_data { + Ok(json) => json, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to convert plist to json: {:?}", + err + ); + String::from("Failed to convert plist data to json") + } + } + } + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to parse statedump plist data: {:?}", + err + ); + String::from("Failed to get plist data") + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::chunks::statedump::Statedump; + + #[test] + fn test_parse_statedump() { + let test_data = [ + 3, 96, 0, 0, 0, 0, 0, 0, 32, 1, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 208, 1, 0, + 0, 14, 0, 0, 0, 13, 179, 213, 232, 0, 0, 0, 0, 118, 4, 0, 0, 0, 0, 0, 128, 92, 216, + 221, 238, 4, 56, 58, 56, 136, 119, 16, 34, 124, 90, 10, 86, 3, 0, 0, 0, 40, 0, 0, 0, + 108, 111, 99, 97, 116, 105, 111, 110, 0, 0, 187, 44, 255, 127, 0, 0, 42, 144, 225, 173, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 78, 41, 126, 255, 127, + 0, 0, 6, 144, 225, 173, 0, 0, 0, 0, 148, 242, 123, 124, 255, 127, 0, 0, 95, 67, 76, 68, + 97, 101, 109, 111, 110, 83, 116, 97, 116, 117, 115, 83, 116, 97, 116, 101, 84, 114, 97, + 99, 107, 101, 114, 83, 116, 97, 116, 101, 0, 144, 225, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 78, 41, 126, 255, 127, 0, 0, 67, 76, 68, 97, 101, + 109, 111, 110, 83, 116, 97, 116, 117, 115, 83, 116, 97, 116, 101, 84, 114, 97, 99, 107, + 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 191, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + let (_, results) = Statedump::parse_statedump(&test_data).unwrap(); + + assert_eq!(results.chunk_tag, 24579); + assert_eq!(results.chunk_subtag, 0); + assert_eq!(results.chunk_data_size, 288); + assert_eq!(results.first_proc_id, 113); + assert_eq!(results.second_proc_id, 464); + assert_eq!(results.ttl, 14); + assert_eq!(results.unknown_reserved, vec![0, 0, 0]); + assert_eq!(results.continuous_time, 3906319117); + assert_eq!(results.activity_id, 9223372036854776950); + assert_eq!(results.uuid, "5CD8DDEE04383A38887710227C5A0A56"); + assert_eq!(results.unknown_data_type, 3); + assert_eq!(results.unknown_data_size, 40); + assert_eq!(results.unknown_object_type_string_1, "location"); + assert_eq!( + results.unknown_object_type_string_2, + "_CLDaemonStatusStateTrackerState" + ); + assert_eq!(results.unknown_name, "CLDaemonStatusStateTracker"); + assert_eq!( + results.statedump_data, + vec![ + 0, 0, 0, 0, 0, 0, 240, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ); + } + + #[test] + fn test_parse_statedump_plist() { + let test_data = [ + 3, 96, 0, 0, 0, 0, 0, 0, 179, 30, 0, 0, 0, 0, 0, 0, 235, 6, 0, 0, 0, 0, 0, 0, 236, 6, + 0, 0, 14, 0, 0, 0, 92, 253, 164, 149, 35, 9, 0, 0, 96, 224, 0, 0, 0, 0, 0, 128, 126, + 93, 152, 85, 209, 204, 56, 45, 184, 235, 37, 160, 48, 212, 178, 250, 1, 0, 0, 0, 187, + 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 101, 98, 67, 111, 110, 116, 101, 110, + 116, 32, 115, 116, 97, 116, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 112, 108, 105, 115, 116, 48, 48, 211, 0, 1, 0, 2, 0, 3, 0, 4, 0, 23, 1, 94, 95, + 16, 18, 77, 101, 109, 111, 114, 121, 32, 85, 115, 97, 103, 101, 32, 83, 116, 97, 116, + 115, 95, 16, 24, 74, 97, 118, 97, 83, 99, 114, 105, 112, 116, 32, 79, 98, 106, 101, 99, + 116, 32, 67, 111, 117, 110, 116, 115, 95, 16, 15, 80, 97, 103, 101, 32, 76, 111, 97, + 100, 32, 84, 105, 109, 101, 115, 217, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, + 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 95, 16, 43, + 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 95, 103, 99, 95, 112, 114, 111, 116, + 101, 99, 116, 101, 100, 95, 103, 108, 111, 98, 97, 108, 95, 111, 98, 106, 101, 99, 116, + 95, 99, 111, 117, 110, 116, 94, 100, 111, 99, 117, 109, 101, 110, 116, 95, 99, 111, + 117, 110, 116, 95, 16, 23, 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 95, 103, 99, + 95, 104, 101, 97, 112, 95, 115, 105, 122, 101, 95, 16, 36, 106, 97, 118, 97, 115, 99, + 114, 105, 112, 116, 95, 103, 99, 95, 104, 101, 97, 112, 95, 101, 120, 116, 114, 97, 95, + 109, 101, 109, 111, 114, 121, 95, 115, 105, 122, 101, 95, 16, 33, 106, 97, 118, 97, + 115, 99, 114, 105, 112, 116, 95, 103, 99, 95, 103, 108, 111, 98, 97, 108, 95, 111, 98, + 106, 101, 99, 116, 95, 99, 111, 117, 110, 116, 95, 16, 26, 106, 97, 118, 97, 115, 99, + 114, 105, 112, 116, 95, 103, 99, 95, 111, 98, 106, 101, 99, 116, 95, 99, 111, 117, 110, + 116, 95, 16, 27, 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 95, 103, 99, 95, 104, + 101, 97, 112, 95, 99, 97, 112, 97, 99, 105, 116, 121, 95, 16, 36, 106, 97, 118, 97, + 115, 99, 114, 105, 112, 116, 95, 103, 99, 95, 112, 114, 111, 116, 101, 99, 116, 101, + 100, 95, 111, 98, 106, 101, 99, 116, 95, 99, 111, 117, 110, 116, 95, 16, 20, 112, 97, + 103, 101, 99, 97, 99, 104, 101, 95, 112, 97, 103, 101, 95, 99, 111, 117, 110, 116, 16, + 2, 16, 24, 18, 1, 28, 208, 17, 18, 0, 96, 153, 97, 16, 9, 18, 0, 1, 181, 224, 18, 1, + 205, 197, 241, 16, 114, 16, 1, 223, 17, 1, 9, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, + 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0, 41, 0, + 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0, 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, + 0, 55, 0, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64, 0, 65, 0, 66, 0, + 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72, 0, 73, 0, 74, 0, 75, 0, 76, 0, 77, 0, 78, 0, 79, + 0, 80, 0, 81, 0, 82, 0, 83, 0, 84, 0, 85, 0, 86, 0, 87, 0, 88, 0, 89, 0, 90, 0, 91, 0, + 92, 0, 93, 0, 94, 0, 95, 0, 96, 0, 97, 0, 98, 0, 99, 0, 100, 0, 101, 0, 102, 0, 103, 0, + 104, 0, 105, 0, 106, 0, 107, 0, 108, 0, 109, 0, 110, 0, 111, 0, 112, 0, 113, 0, 114, 0, + 115, 0, 116, 0, 117, 0, 118, 0, 119, 0, 120, 0, 121, 0, 122, 0, 123, 0, 124, 0, 125, 0, + 126, 0, 127, 0, 128, 0, 129, 0, 130, 0, 131, 0, 132, 0, 133, 0, 134, 0, 135, 0, 136, 0, + 137, 0, 138, 0, 139, 0, 140, 0, 141, 0, 142, 0, 143, 0, 144, 0, 145, 0, 146, 0, 147, 0, + 148, 0, 149, 0, 150, 0, 151, 0, 152, 0, 153, 0, 154, 0, 155, 0, 156, 0, 157, 0, 158, 0, + 159, 0, 160, 0, 161, 0, 162, 0, 163, 0, 164, 0, 165, 0, 166, 0, 167, 0, 168, 0, 169, 0, + 170, 0, 171, 0, 172, 0, 173, 0, 174, 0, 175, 0, 176, 0, 177, 0, 178, 0, 179, 0, 180, 0, + 181, 0, 182, 0, 183, 0, 184, 0, 185, 0, 186, 0, 187, 0, 188, 0, 189, 0, 190, 0, 191, 0, + 192, 0, 193, 0, 194, 0, 195, 0, 196, 0, 197, 0, 198, 0, 199, 0, 200, 0, 201, 0, 202, 0, + 203, 0, 204, 0, 205, 0, 206, 0, 207, 0, 208, 0, 209, 0, 210, 0, 211, 0, 212, 0, 213, 0, + 214, 0, 215, 0, 216, 0, 217, 0, 218, 0, 219, 0, 220, 0, 221, 0, 222, 0, 223, 0, 224, 0, + 225, 0, 226, 0, 227, 0, 228, 0, 229, 0, 230, 0, 231, 0, 232, 0, 233, 0, 234, 0, 235, 0, + 236, 0, 237, 0, 238, 0, 239, 0, 240, 0, 241, 0, 242, 0, 243, 0, 244, 0, 245, 0, 246, 0, + 247, 0, 248, 0, 249, 0, 250, 0, 251, 0, 252, 0, 253, 0, 254, 0, 255, 1, 0, 1, 1, 1, 2, + 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, + 16, 1, 17, 1, 18, 1, 19, 1, 20, 1, 21, 1, 22, 1, 23, 1, 24, 1, 25, 1, 26, 1, 27, 1, 28, + 1, 29, 1, 30, 1, 31, 1, 32, 1, 33, 1, 34, 0, 18, 0, 22, 0, 22, 0, 22, 0, 22, 0, 14, 0, + 22, 0, 22, 0, 22, 0, 22, 1, 35, 1, 36, 0, 22, 0, 14, 1, 37, 1, 38, 0, 22, 1, 39, 1, 40, + 1, 41, 1, 42, 1, 43, 0, 22, 0, 14, 1, 44, 0, 22, 1, 45, 0, 22, 1, 46, 0, 18, 0, 22, 0, + 22, 0, 22, 1, 39, 0, 22, 0, 14, 0, 14, 0, 14, 0, 22, 1, 39, 0, 22, 0, 22, 1, 47, 1, 44, + 1, 48, 0, 18, 1, 49, 1, 35, 1, 46, 1, 50, 0, 14, 0, 22, 0, 22, 1, 51, 1, 35, 0, 22, 1, + 52, 0, 22, 1, 35, 1, 46, 0, 18, 1, 44, 1, 53, 1, 47, 1, 39, 0, 18, 0, 22, 0, 18, 0, 22, + 1, 54, 0, 22, 0, 18, 0, 22, 1, 45, 1, 46, 0, 22, 0, 18, 0, 18, 1, 35, 0, 22, 1, 55, 0, + 22, 0, 18, 1, 39, 1, 56, 0, 18, 0, 22, 0, 22, 0, 22, 0, 22, 1, 57, 1, 35, 0, 22, 1, 46, + 1, 58, 0, 14, 0, 18, 1, 59, 0, 14, 0, 14, 1, 46, 0, 14, 0, 14, 0, 14, 1, 39, 1, 60, 1, + 44, 0, 14, 0, 22, 0, 14, 1, 39, 0, 14, 0, 14, 1, 46, 1, 61, 0, 18, 0, 22, 0, 22, 1, 62, + 1, 63, 0, 22, 0, 22, 1, 64, 0, 22, 1, 65, 1, 57, 0, 22, 0, 18, 1, 39, 1, 66, 1, 67, 0, + 18, 0, 18, 0, 22, 1, 68, 1, 45, 1, 69, 0, 14, 1, 70, 0, 22, 1, 46, 0, 14, 1, 71, 0, 14, + 0, 22, 1, 72, 0, 18, 1, 47, 0, 22, 0, 14, 1, 39, 0, 14, 1, 57, 1, 73, 0, 22, 1, 35, 1, + 39, 0, 14, 1, 44, 0, 14, 0, 14, 1, 37, 0, 22, 0, 18, 0, 22, 0, 18, 1, 47, 1, 74, 1, 73, + 1, 35, 1, 57, 1, 46, 0, 14, 1, 75, 0, 14, 0, 22, 1, 76, 0, 22, 0, 22, 1, 47, 1, 77, 1, + 35, 0, 14, 1, 78, 1, 78, 1, 44, 0, 22, 1, 44, 1, 57, 1, 79, 1, 47, 1, 47, 0, 22, 0, 18, + 1, 35, 1, 80, 1, 81, 1, 35, 1, 35, 0, 22, 0, 22, 0, 14, 1, 46, 0, 14, 1, 45, 0, 14, 0, + 22, 0, 14, 1, 82, 1, 57, 1, 83, 0, 14, 1, 37, 0, 14, 1, 47, 1, 39, 1, 84, 0, 14, 1, 39, + 1, 85, 1, 39, 1, 39, 0, 22, 0, 22, 0, 14, 0, 18, 1, 86, 0, 18, 1, 87, 1, 88, 0, 22, 1, + 57, 1, 47, 0, 22, 0, 22, 1, 47, 1, 44, 0, 18, 0, 18, 1, 39, 0, 22, 0, 22, 0, 18, 1, 89, + 1, 35, 0, 18, 1, 90, 0, 18, 1, 91, 1, 39, 1, 47, 0, 22, 1, 92, 1, 47, 1, 47, 0, 22, 1, + 35, 1, 47, 1, 39, 0, 15, 1, 46, 1, 93, 1, 44, 94, 83, 116, 114, 117, 99, 116, 117, 114, + 101, 67, 104, 97, 105, 110, 95, 16, 18, 72, 84, 77, 76, 72, 101, 97, 100, 105, 110, + 103, 69, 108, 101, 109, 101, 110, 116, 89, 71, 101, 110, 101, 114, 97, 116, 111, 114, + 95, 16, 25, 72, 84, 77, 76, 84, 105, 116, 108, 101, 69, 108, 101, 109, 101, 110, 116, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 20, 85, 105, 110, 116, 49, 54, 65, + 114, 114, 97, 121, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 23, 83, 86, 71, + 68, 101, 102, 115, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 90, 77, 111, 117, 115, 101, 69, 118, 101, 110, 116, 95, 16, 16, 72, 84, 77, + 76, 79, 76, 105, 115, 116, 69, 108, 101, 109, 101, 110, 116, 95, 16, 23, 77, 117, 116, + 97, 116, 105, 111, 110, 82, 101, 99, 111, 114, 100, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 34, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, + 69, 118, 101, 110, 116, 84, 97, 114, 103, 101, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 92, 68, 111, 99, 117, 109, 101, 110, 116, 84, 121, 112, 101, 95, 16, 27, 72, + 84, 77, 76, 85, 110, 107, 110, 111, 119, 110, 69, 108, 101, 109, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 25, 72, 84, 77, 76, 84, 97, 98, 108, + 101, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, + 16, 18, 67, 117, 115, 116, 111, 109, 71, 101, 116, 116, 101, 114, 83, 101, 116, 116, + 101, 114, 95, 16, 23, 83, 86, 71, 80, 97, 116, 104, 69, 108, 101, 109, 101, 110, 116, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 16, 83, 116, 111, 114, 97, 103, + 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 91, 87, 101, 98, 65, 115, 115, 101, + 109, 98, 108, 121, 93, 65, 115, 121, 110, 99, 70, 117, 110, 99, 116, 105, 111, 110, 92, + 71, 108, 111, 98, 97, 108, 79, 98, 106, 101, 99, 116, 87, 67, 111, 109, 109, 101, 110, + 116, 95, 16, 17, 83, 116, 114, 117, 99, 116, 117, 114, 101, 82, 97, 114, 101, 68, 97, + 116, 97, 95, 16, 26, 85, 110, 108, 105, 110, 107, 101, 100, 70, 117, 110, 99, 116, 105, + 111, 110, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 93, 72, 97, 115, 104, 77, 97, + 112, 66, 117, 99, 107, 101, 116, 95, 16, 25, 85, 110, 108, 105, 110, 107, 101, 100, 70, + 117, 110, 99, 116, 105, 111, 110, 67, 111, 100, 101, 66, 108, 111, 99, 107, 95, 16, 16, + 72, 84, 77, 76, 84, 105, 116, 108, 101, 69, 108, 101, 109, 101, 110, 116, 94, 88, 77, + 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, 95, 16, 20, 83, 99, 111, 112, + 101, 100, 65, 114, 103, 117, 109, 101, 110, 116, 115, 84, 97, 98, 108, 101, 95, 16, 19, + 80, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 79, 98, 115, 101, 114, 118, 101, + 114, 86, 67, 97, 108, 108, 101, 101, 95, 16, 23, 88, 77, 76, 72, 116, 116, 112, 82, + 101, 113, 117, 101, 115, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 87, 105, + 110, 100, 111, 119, 95, 16, 21, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, + 76, 105, 110, 107, 69, 114, 114, 111, 114, 92, 67, 83, 83, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 28, 72, 84, 77, 76, 70, 105, 101, 108, 100, 83, 101, 116, 69, + 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 17, + 68, 79, 77, 73, 109, 112, 108, 101, 109, 101, 110, 116, 97, 116, 105, 111, 110, 95, 16, + 25, 72, 84, 77, 76, 85, 76, 105, 115, 116, 69, 108, 101, 109, 101, 110, 116, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 95, 16, 26, 72, 84, 77, 76, 83, 101, 108, 101, 99, + 116, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, + 16, 28, 72, 84, 77, 76, 84, 97, 98, 108, 101, 82, 111, 119, 69, 108, 101, 109, 101, + 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 16, 68, 111, 99, 117, + 109, 101, 110, 116, 70, 114, 97, 103, 109, 101, 110, 116, 95, 16, 19, 83, 86, 71, 69, + 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 85, 69, 118, + 101, 110, 116, 87, 74, 83, 80, 114, 111, 120, 121, 95, 16, 21, 68, 111, 99, 117, 109, + 101, 110, 116, 84, 121, 112, 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, + 24, 72, 84, 77, 76, 76, 105, 110, 107, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 28, 67, 83, 83, 83, 116, 121, 108, 101, 68, 101, + 99, 108, 97, 114, 97, 116, 105, 111, 110, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 95, 16, 25, 72, 84, 77, 76, 73, 109, 97, 103, 101, 69, 108, 101, 109, 101, 110, 116, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 115, 116, 114, 105, 110, 103, 95, 16, + 18, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, 77, 111, 100, 117, 108, 101, + 87, 80, 114, 111, 109, 105, 115, 101, 92, 68, 79, 77, 69, 120, 99, 101, 112, 116, 105, + 111, 110, 95, 16, 17, 83, 86, 71, 65, 110, 105, 109, 97, 116, 101, 100, 83, 116, 114, + 105, 110, 103, 95, 16, 24, 85, 110, 108, 105, 110, 107, 101, 100, 80, 114, 111, 103, + 114, 97, 109, 67, 111, 100, 101, 66, 108, 111, 99, 107, 95, 16, 15, 67, 114, 121, 112, + 116, 111, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 30, 67, 117, 115, 116, + 111, 109, 69, 108, 101, 109, 101, 110, 116, 82, 101, 103, 105, 115, 116, 114, 121, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 94, 69, 118, 97, 108, 69, 120, 101, 99, 117, + 116, 97, 98, 108, 101, 86, 83, 116, 114, 105, 110, 103, 95, 16, 32, 72, 84, 77, 76, 84, + 97, 98, 108, 101, 83, 101, 99, 116, 105, 111, 110, 69, 108, 101, 109, 101, 110, 116, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 83, 67, 83, 83, 95, 16, 18, 70, 117, 110, + 99, 116, 105, 111, 110, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 95, 16, 21, 68, + 79, 77, 69, 120, 99, 101, 112, 116, 105, 111, 110, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 16, 80, 114, 111, 103, 114, 97, 109, 67, 111, 100, 101, 66, 108, 111, + 99, 107, 95, 16, 42, 82, 101, 97, 100, 97, 98, 108, 101, 83, 116, 114, 101, 97, 109, + 66, 89, 79, 66, 82, 101, 97, 100, 101, 114, 80, 114, 105, 118, 97, 116, 101, 67, 111, + 110, 115, 116, 114, 117, 99, 116, 111, 114, 93, 65, 115, 121, 110, 99, 73, 116, 101, + 114, 97, 116, 111, 114, 94, 83, 86, 71, 80, 97, 116, 104, 69, 108, 101, 109, 101, 110, + 116, 95, 16, 16, 70, 117, 110, 99, 116, 105, 111, 110, 82, 97, 114, 101, 68, 97, 116, + 97, 95, 16, 24, 72, 84, 77, 76, 66, 111, 100, 121, 69, 108, 101, 109, 101, 110, 116, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 19, 83, 112, 97, 114, 115, 101, 65, + 114, 114, 97, 121, 86, 97, 108, 117, 101, 77, 97, 112, 95, 16, 21, 65, 115, 121, 110, + 99, 70, 114, 111, 109, 83, 121, 110, 99, 73, 116, 101, 114, 97, 116, 111, 114, 90, 84, + 114, 101, 101, 87, 97, 108, 107, 101, 114, 95, 16, 24, 87, 101, 98, 65, 115, 115, 101, + 109, 98, 108, 121, 46, 82, 117, 110, 116, 105, 109, 101, 69, 114, 114, 111, 114, 95, + 16, 15, 72, 84, 77, 76, 66, 97, 115, 101, 69, 108, 101, 109, 101, 110, 116, 88, 78, + 111, 100, 101, 76, 105, 115, 116, 89, 78, 97, 118, 105, 103, 97, 116, 111, 114, 95, 16, + 26, 74, 83, 71, 108, 111, 98, 97, 108, 76, 101, 120, 105, 99, 97, 108, 69, 110, 118, + 105, 114, 111, 110, 109, 101, 110, 116, 95, 16, 24, 85, 82, 76, 83, 101, 97, 114, 99, + 104, 80, 97, 114, 97, 109, 115, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 16, + 72, 84, 77, 76, 73, 110, 112, 117, 116, 69, 108, 101, 109, 101, 110, 116, 95, 16, 20, + 69, 118, 101, 110, 116, 84, 97, 114, 103, 101, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 18, 72, 84, 77, 76, 68, 101, 116, 97, 105, 108, 115, 69, 108, 101, + 109, 101, 110, 116, 95, 16, 24, 73, 110, 115, 112, 101, 99, 116, 111, 114, 73, 110, + 115, 116, 114, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 87, 66, 111, 111, 108, + 101, 97, 110, 95, 16, 25, 72, 84, 77, 76, 73, 110, 112, 117, 116, 69, 108, 101, 109, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 20, 68, 79, 77, 82, + 101, 99, 116, 76, 105, 115, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, + 20, 74, 83, 76, 101, 120, 105, 99, 97, 108, 69, 110, 118, 105, 114, 111, 110, 109, 101, + 110, 116, 95, 16, 25, 77, 117, 116, 97, 116, 105, 111, 110, 79, 98, 115, 101, 114, 118, + 101, 114, 80, 114, 111, 116, 111, 116, 121, 112, 101, 94, 65, 114, 114, 97, 121, 32, + 73, 116, 101, 114, 97, 116, 111, 114, 93, 84, 101, 120, 116, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 95, 16, 17, 73, 110, 102, 101, 114, 114, 101, 100, 84, 121, 112, + 101, 84, 97, 98, 108, 101, 95, 16, 20, 72, 84, 77, 76, 84, 97, 98, 108, 101, 67, 101, + 108, 108, 69, 108, 101, 109, 101, 110, 116, 95, 16, 15, 68, 79, 77, 82, 101, 99, 116, + 82, 101, 97, 100, 79, 110, 108, 121, 95, 16, 27, 83, 86, 71, 67, 108, 105, 112, 80, 97, + 116, 104, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 95, 16, 18, 87, 101, 98, 83, 111, 99, 107, 101, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 94, 83, 86, 71, 68, 101, 102, 115, 69, 108, 101, 109, 101, 110, 116, 85, 82, + 97, 110, 103, 101, 95, 16, 17, 80, 114, 111, 103, 114, 97, 109, 69, 120, 101, 99, 117, + 116, 97, 98, 108, 101, 87, 67, 111, 110, 115, 111, 108, 101, 95, 16, 49, 82, 101, 97, + 100, 97, 98, 108, 101, 83, 116, 114, 101, 97, 109, 68, 101, 102, 97, 117, 108, 116, 67, + 111, 110, 116, 114, 111, 108, 108, 101, 114, 80, 114, 105, 118, 97, 116, 101, 67, 111, + 110, 115, 116, 114, 117, 99, 116, 111, 114, 95, 16, 17, 72, 84, 77, 76, 65, 110, 99, + 104, 111, 114, 69, 108, 101, 109, 101, 110, 116, 95, 16, 16, 85, 73, 69, 118, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 78, 117, 109, 98, 101, 114, 84, + 84, 101, 120, 116, 95, 16, 19, 80, 97, 103, 101, 84, 114, 97, 110, 115, 105, 116, 105, + 111, 110, 69, 118, 101, 110, 116, 95, 16, 25, 72, 84, 77, 76, 76, 97, 98, 101, 108, 69, + 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 46, + 82, 101, 97, 100, 97, 98, 108, 101, 66, 121, 116, 101, 83, 116, 114, 101, 97, 109, 67, + 111, 110, 116, 114, 111, 108, 108, 101, 114, 80, 114, 105, 118, 97, 116, 101, 67, 111, + 110, 115, 116, 114, 117, 99, 116, 111, 114, 95, 16, 27, 83, 86, 71, 71, 114, 97, 112, + 104, 105, 99, 115, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 19, 77, 111, 117, 115, 101, 69, 118, 101, 110, 116, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 22, 83, 86, 71, 83, 86, 71, 69, 108, 101, 109, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 15, 72, 84, 77, 76, + 72, 101, 97, 100, 69, 108, 101, 109, 101, 110, 116, 85, 65, 114, 114, 97, 121, 95, 16, + 20, 88, 80, 97, 116, 104, 82, 101, 115, 117, 108, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 87, 83, 116, 111, 114, 97, 103, 101, 95, 16, 24, 72, 84, 77, 76, 66, 97, + 115, 101, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 95, 16, 15, 72, 84, 77, 76, 70, 111, 114, 109, 69, 108, 101, 109, 101, 110, 116, 92, + 78, 97, 109, 101, 100, 78, 111, 100, 101, 77, 97, 112, 95, 16, 28, 80, 97, 103, 101, + 84, 114, 97, 110, 115, 105, 116, 105, 111, 110, 69, 118, 101, 110, 116, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 28, 72, 84, 77, 76, 84, 101, 109, 112, 108, 97, + 116, 101, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 95, 16, 15, 87, 105, 110, 100, 111, 119, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 94, 72, 84, 77, 76, 67, 111, 108, 108, 101, 99, 116, 105, 111, 110, 95, 16, 17, 87, + 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, 84, 97, 98, 108, 101, 95, 16, 28, + 72, 84, 77, 76, 84, 101, 120, 116, 65, 114, 101, 97, 69, 108, 101, 109, 101, 110, 116, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 93, 65, 116, 116, 114, 80, 114, 111, 116, + 111, 116, 121, 112, 101, 87, 87, 101, 97, 107, 77, 97, 112, 89, 65, 114, 103, 117, 109, + 101, 110, 116, 115, 95, 16, 18, 68, 79, 77, 80, 97, 114, 115, 101, 114, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 26, 80, 101, 114, 102, 111, 114, 109, 97, 110, + 99, 101, 84, 105, 109, 105, 110, 103, 80, 114, 111, 116, 111, 116, 121, 112, 101, 92, + 73, 110, 102, 101, 114, 114, 101, 100, 84, 121, 112, 101, 95, 16, 28, 80, 101, 114, + 102, 111, 114, 109, 97, 110, 99, 101, 79, 98, 115, 101, 114, 118, 101, 114, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 95, 16, 24, 68, 79, 77, 65, 116, 116, 114, 105, 98, + 117, 116, 101, 71, 101, 116, 116, 101, 114, 83, 101, 116, 116, 101, 114, 93, 78, 111, + 100, 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 85, 69, 114, 114, 111, 114, 95, + 16, 20, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, 73, 110, 115, 116, 97, + 110, 99, 101, 95, 16, 24, 72, 84, 77, 76, 83, 112, 97, 110, 69, 108, 101, 109, 101, + 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 20, 72, 84, 77, 76, 80, + 97, 114, 97, 103, 114, 97, 112, 104, 69, 108, 101, 109, 101, 110, 116, 93, 80, 114, + 111, 112, 101, 114, 116, 121, 84, 97, 98, 108, 101, 95, 16, 15, 83, 116, 114, 105, 110, + 103, 32, 73, 116, 101, 114, 97, 116, 111, 114, 92, 72, 84, 77, 76, 68, 111, 99, 117, + 109, 101, 110, 116, 95, 16, 20, 80, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 25, 69, 120, 101, 99, 117, 116, 97, 98, + 108, 101, 84, 111, 67, 111, 100, 101, 66, 108, 111, 99, 107, 69, 100, 103, 101, 94, 67, + 97, 108, 108, 98, 97, 99, 107, 79, 98, 106, 101, 99, 116, 91, 72, 84, 77, 76, 69, 108, + 101, 109, 101, 110, 116, 94, 69, 118, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 19, 67, 83, 83, 83, 116, 121, 108, 101, 68, 101, 99, 108, 97, 114, + 97, 116, 105, 111, 110, 95, 16, 22, 80, 114, 111, 103, 114, 101, 115, 115, 69, 118, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 23, 72, 84, 77, 76, + 84, 97, 98, 108, 101, 83, 101, 99, 116, 105, 111, 110, 69, 108, 101, 109, 101, 110, + 116, 95, 16, 23, 72, 84, 77, 76, 80, 114, 101, 69, 108, 101, 109, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 92, 74, 83, 70, 105, 120, 101, 100, 65, 114, + 114, 97, 121, 93, 83, 86, 71, 83, 86, 71, 69, 108, 101, 109, 101, 110, 116, 95, 16, 26, + 68, 79, 77, 73, 109, 112, 108, 101, 109, 101, 110, 116, 97, 116, 105, 111, 110, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 86, 82, 101, 103, 69, 120, 112, 88, 73, 116, + 101, 114, 97, 116, 111, 114, 95, 16, 23, 72, 84, 77, 76, 68, 105, 118, 69, 108, 101, + 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 19, 84, 114, + 101, 101, 87, 97, 108, 107, 101, 114, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, + 16, 21, 85, 110, 108, 105, 110, 107, 101, 100, 69, 118, 97, 108, 67, 111, 100, 101, 66, + 108, 111, 99, 107, 95, 16, 16, 68, 79, 77, 82, 101, 99, 116, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 95, 16, 24, 72, 84, 77, 76, 70, 111, 114, 109, 69, 108, 101, 109, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 16, 69, 108, 101, + 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 83, 77, 97, 112, 95, + 16, 27, 72, 84, 77, 76, 68, 101, 116, 97, 105, 108, 115, 69, 108, 101, 109, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 25, 72, 84, 77, 76, 83, 116, + 121, 108, 101, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, + 101, 95, 16, 22, 67, 104, 97, 114, 97, 99, 116, 101, 114, 68, 97, 116, 97, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 95, 16, 25, 68, 111, 99, 117, 109, 101, 110, 116, + 70, 114, 97, 103, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 94, + 72, 84, 77, 76, 80, 114, 101, 69, 108, 101, 109, 101, 110, 116, 95, 16, 25, 72, 84, 77, + 76, 79, 76, 105, 115, 116, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 93, 72, 84, 77, 76, 66, 82, 69, 108, 101, 109, 101, 110, 116, 92, + 77, 111, 100, 117, 108, 101, 76, 111, 97, 100, 101, 114, 91, 68, 79, 77, 82, 101, 99, + 116, 76, 105, 115, 116, 95, 16, 22, 65, 115, 121, 110, 99, 71, 101, 110, 101, 114, 97, + 116, 111, 114, 70, 117, 110, 99, 116, 105, 111, 110, 87, 72, 105, 115, 116, 111, 114, + 121, 95, 16, 24, 73, 110, 116, 101, 114, 110, 97, 108, 80, 114, 111, 109, 105, 115, + 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 17, 78, 111, 100, 101, 76, + 105, 115, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 92, 71, 101, 116, 116, 101, + 114, 83, 101, 116, 116, 101, 114, 95, 16, 17, 71, 101, 110, 101, 114, 97, 116, 111, + 114, 70, 117, 110, 99, 116, 105, 111, 110, 95, 16, 16, 67, 111, 109, 109, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 20, 72, 84, 77, 76, 69, 108, + 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 43, 82, + 101, 97, 100, 97, 98, 108, 101, 83, 116, 114, 101, 97, 109, 66, 89, 79, 66, 82, 101, + 113, 117, 101, 115, 116, 80, 114, 105, 118, 97, 116, 101, 67, 111, 110, 115, 116, 114, + 117, 99, 116, 111, 114, 95, 16, 22, 72, 84, 77, 76, 66, 82, 69, 108, 101, 109, 101, + 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 15, 72, 84, 77, 76, 77, + 101, 116, 97, 69, 108, 101, 109, 101, 110, 116, 84, 65, 116, 116, 114, 88, 68, 111, 99, + 117, 109, 101, 110, 116, 89, 83, 116, 114, 117, 99, 116, 117, 114, 101, 95, 16, 26, 83, + 86, 71, 65, 110, 105, 109, 97, 116, 101, 100, 83, 116, 114, 105, 110, 103, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 84, 66, 108, 111, 98, 95, 16, 17, 76, 111, 99, 97, + 116, 105, 111, 110, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 16, 78, 97, + 116, 105, 118, 101, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 84, 74, 83, 79, 78, + 95, 16, 29, 72, 84, 77, 76, 84, 97, 98, 108, 101, 67, 101, 108, 108, 69, 108, 101, 109, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 115, 121, 109, 98, 111, + 108, 83, 83, 101, 116, 95, 16, 16, 67, 97, 108, 108, 98, 97, 99, 107, 70, 117, 110, 99, + 116, 105, 111, 110, 93, 66, 108, 111, 98, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 95, 16, 18, 83, 86, 71, 67, 108, 105, 112, 80, 97, 116, 104, 69, 108, 101, 109, 101, + 110, 116, 95, 16, 17, 68, 111, 99, 117, 109, 101, 110, 116, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 93, 73, 110, 102, 101, 114, 114, 101, 100, 86, 97, 108, 117, 101, + 95, 16, 29, 72, 84, 77, 76, 80, 97, 114, 97, 103, 114, 97, 112, 104, 69, 108, 101, 109, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 24, 72, 84, 77, 76, + 77, 101, 116, 97, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 89, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 83, 121, 109, 98, 111, + 108, 88, 76, 111, 99, 97, 116, 105, 111, 110, 95, 16, 15, 72, 84, 77, 76, 76, 105, 110, + 107, 69, 108, 101, 109, 101, 110, 116, 92, 68, 79, 77, 84, 111, 107, 101, 110, 76, 105, + 115, 116, 95, 16, 26, 72, 84, 77, 76, 83, 99, 114, 105, 112, 116, 69, 108, 101, 109, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 16, 77, 117, 116, + 97, 116, 105, 111, 110, 79, 98, 115, 101, 114, 118, 101, 114, 95, 16, 26, 72, 84, 77, + 76, 79, 112, 116, 105, 111, 110, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, + 111, 116, 121, 112, 101, 95, 16, 15, 85, 82, 76, 83, 101, 97, 114, 99, 104, 80, 97, + 114, 97, 109, 115, 95, 16, 18, 78, 97, 118, 105, 103, 97, 116, 111, 114, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 45, 82, 101, 97, 100, 97, 98, 108, 101, 83, 116, + 114, 101, 97, 109, 68, 101, 102, 97, 117, 108, 116, 82, 101, 97, 100, 101, 114, 80, + 114, 105, 118, 97, 116, 101, 67, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 87, + 87, 101, 97, 107, 83, 101, 116, 95, 16, 16, 72, 84, 77, 76, 83, 116, 121, 108, 101, 69, + 108, 101, 109, 101, 110, 116, 94, 82, 97, 110, 103, 101, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 25, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, + 116, 69, 118, 101, 110, 116, 84, 97, 114, 103, 101, 116, 95, 16, 17, 72, 84, 77, 76, + 66, 117, 116, 116, 111, 110, 69, 108, 101, 109, 101, 110, 116, 94, 72, 84, 77, 76, 68, + 105, 118, 69, 108, 101, 109, 101, 110, 116, 95, 16, 19, 72, 84, 77, 76, 70, 105, 101, + 108, 100, 83, 101, 116, 69, 108, 101, 109, 101, 110, 116, 95, 16, 24, 74, 83, 80, 114, + 111, 112, 101, 114, 116, 121, 78, 97, 109, 101, 69, 110, 117, 109, 101, 114, 97, 116, + 111, 114, 95, 16, 26, 72, 84, 77, 76, 66, 117, 116, 116, 111, 110, 69, 108, 101, 109, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 94, 65, 115, 121, 110, 99, + 71, 101, 110, 101, 114, 97, 116, 111, 114, 95, 16, 21, 78, 97, 109, 101, 100, 78, 111, + 100, 101, 77, 97, 112, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 19, 72, 84, + 77, 76, 84, 97, 98, 108, 101, 82, 111, 119, 69, 108, 101, 109, 101, 110, 116, 95, 16, + 16, 74, 83, 68, 79, 77, 87, 105, 110, 100, 111, 119, 80, 114, 111, 120, 121, 88, 70, + 117, 110, 99, 116, 105, 111, 110, 95, 16, 19, 72, 84, 77, 76, 84, 101, 109, 112, 108, + 97, 116, 101, 69, 108, 101, 109, 101, 110, 116, 95, 16, 15, 72, 84, 77, 76, 66, 111, + 100, 121, 69, 108, 101, 109, 101, 110, 116, 91, 83, 121, 109, 98, 111, 108, 84, 97, 98, + 108, 101, 95, 16, 22, 72, 84, 77, 76, 76, 73, 69, 108, 101, 109, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 15, 72, 84, 77, 76, 72, 116, 109, 108, + 69, 108, 101, 109, 101, 110, 116, 91, 80, 101, 114, 102, 111, 114, 109, 97, 110, 99, + 101, 89, 87, 101, 98, 83, 111, 99, 107, 101, 116, 86, 67, 114, 121, 112, 116, 111, 95, + 16, 20, 65, 114, 114, 97, 121, 66, 117, 102, 102, 101, 114, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 95, 16, 16, 72, 84, 77, 76, 85, 76, 105, 115, 116, 69, 108, 101, + 109, 101, 110, 116, 95, 16, 18, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, + 77, 101, 109, 111, 114, 121, 91, 88, 80, 97, 116, 104, 82, 101, 115, 117, 108, 116, 95, + 16, 16, 72, 84, 77, 76, 73, 109, 97, 103, 101, 69, 108, 101, 109, 101, 110, 116, 90, + 78, 111, 100, 101, 70, 105, 108, 116, 101, 114, 95, 16, 21, 72, 84, 77, 76, 68, 111, + 99, 117, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 84, 77, 97, + 116, 104, 95, 16, 36, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, + 80, 114, 111, 103, 114, 101, 115, 115, 69, 118, 101, 110, 116, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 95, 16, 30, 80, 114, 111, 109, 105, 115, 101, 82, 101, 106, 101, + 99, 116, 105, 111, 110, 69, 118, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, + 101, 95, 16, 26, 72, 84, 77, 76, 65, 110, 99, 104, 111, 114, 69, 108, 101, 109, 101, + 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 21, 68, 79, 77, 84, 111, + 107, 101, 110, 76, 105, 115, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 92, 77, + 97, 112, 32, 73, 116, 101, 114, 97, 116, 111, 114, 95, 16, 24, 87, 101, 98, 65, 115, + 115, 101, 109, 98, 108, 121, 46, 67, 111, 109, 112, 105, 108, 101, 69, 114, 114, 111, + 114, 95, 16, 24, 68, 79, 77, 82, 101, 99, 116, 82, 101, 97, 100, 79, 110, 108, 121, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 89, 68, 79, 77, 80, 97, 114, 115, 101, 114, 95, + 16, 27, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, 80, 114, 111, + 103, 114, 101, 115, 115, 69, 118, 101, 110, 116, 92, 83, 101, 116, 32, 73, 116, 101, + 114, 97, 116, 111, 114, 95, 16, 17, 70, 117, 110, 99, 116, 105, 111, 110, 67, 111, 100, + 101, 66, 108, 111, 99, 107, 89, 69, 120, 99, 101, 112, 116, 105, 111, 110, 95, 16, 16, + 80, 114, 111, 109, 105, 115, 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 79, + 98, 106, 101, 99, 116, 95, 16, 16, 72, 84, 77, 76, 84, 97, 98, 108, 101, 69, 108, 101, + 109, 101, 110, 116, 93, 72, 84, 77, 76, 76, 73, 69, 108, 101, 109, 101, 110, 116, 95, + 16, 27, 72, 84, 77, 76, 72, 101, 97, 100, 105, 110, 103, 69, 108, 101, 109, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 91, 69, 118, 101, 110, 116, 84, 97, + 114, 103, 101, 116, 95, 16, 16, 72, 105, 115, 116, 111, 114, 121, 80, 114, 111, 116, + 111, 116, 121, 112, 101, 87, 68, 79, 77, 82, 101, 99, 116, 84, 78, 111, 100, 101, 87, + 69, 108, 101, 109, 101, 110, 116, 93, 69, 118, 97, 108, 67, 111, 100, 101, 66, 108, + 111, 99, 107, 95, 16, 16, 72, 84, 77, 76, 76, 97, 98, 101, 108, 69, 108, 101, 109, 101, + 110, 116, 95, 16, 24, 72, 84, 77, 76, 72, 116, 109, 108, 69, 108, 101, 109, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 23, 72, 84, 77, 76, 67, 111, + 108, 108, 101, 99, 116, 105, 111, 110, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, + 16, 17, 72, 84, 77, 76, 83, 99, 114, 105, 112, 116, 69, 108, 101, 109, 101, 110, 116, + 95, 16, 16, 87, 105, 110, 100, 111, 119, 80, 114, 111, 112, 101, 114, 116, 105, 101, + 115, 95, 16, 15, 72, 84, 77, 76, 83, 112, 97, 110, 69, 108, 101, 109, 101, 110, 116, + 95, 16, 24, 72, 84, 77, 76, 72, 101, 97, 100, 69, 108, 101, 109, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 17, 1, 28, 16, 78, 16, 3, 17, 3, 31, 16, 18, + 16, 39, 16, 5, 17, 2, 239, 17, 79, 93, 17, 1, 46, 17, 22, 193, 16, 4, 16, 12, 16, 8, + 16, 6, 17, 125, 241, 16, 29, 16, 77, 16, 15, 17, 21, 197, 16, 132, 17, 1, 24, 17, 4, + 197, 17, 2, 158, 16, 7, 17, 1, 77, 17, 2, 169, 17, 19, 171, 16, 98, 16, 30, 16, 108, + 17, 20, 14, 17, 13, 246, 16, 89, 17, 6, 174, 17, 5, 78, 16, 118, 17, 3, 79, 17, 13, 22, + 17, 7, 160, 16, 22, 16, 224, 16, 14, 17, 35, 209, 17, 2, 125, 16, 13, 17, 28, 63, 16, + 20, 16, 202, 17, 1, 95, 16, 174, 17, 42, 222, 17, 6, 122, 16, 37, 16, 41, 16, 19, 17, + 5, 73, 17, 25, 87, 16, 128, 17, 3, 103, 16, 157, 161, 1, 95, 51, 65, 195, 217, 198, + 124, 0, 194, 240, 0, 8, 0, 21, 0, 42, 0, 69, 0, 87, 0, 124, 0, 170, 0, 185, 0, 211, 0, + 250, 1, 30, 1, 59, 1, 89, 1, 128, 1, 151, 1, 153, 1, 155, 1, 160, 1, 165, 1, 167, 1, + 172, 1, 177, 1, 179, 1, 181, 5, 221, 5, 236, 6, 1, 6, 11, 6, 39, 6, 62, 6, 88, 6, 99, + 6, 118, 6, 144, 6, 181, 6, 194, 6, 224, 6, 252, 7, 17, 7, 43, 7, 62, 7, 74, 7, 88, 7, + 101, 7, 109, 7, 129, 7, 158, 7, 172, 7, 200, 7, 219, 7, 234, 8, 1, 8, 23, 8, 30, 8, 56, + 8, 63, 8, 87, 8, 100, 8, 131, 8, 151, 8, 179, 8, 208, 8, 239, 9, 2, 9, 24, 9, 30, 9, + 38, 9, 62, 9, 89, 9, 120, 9, 148, 9, 155, 9, 176, 9, 184, 9, 197, 9, 217, 9, 244, 10, + 6, 10, 39, 10, 54, 10, 61, 10, 96, 10, 100, 10, 121, 10, 145, 10, 164, 10, 209, 10, + 223, 10, 238, 11, 1, 11, 28, 11, 50, 11, 74, 11, 85, 11, 112, 11, 130, 11, 139, 11, + 149, 11, 178, 11, 205, 11, 224, 11, 247, 12, 12, 12, 39, 12, 47, 12, 75, 12, 98, 12, + 121, 12, 149, 12, 164, 12, 178, 12, 198, 12, 221, 12, 239, 13, 13, 13, 34, 13, 49, 13, + 55, 13, 75, 13, 83, 13, 135, 13, 155, 13, 174, 13, 181, 13, 186, 13, 208, 13, 236, 14, + 29, 14, 59, 14, 81, 14, 106, 14, 124, 14, 130, 14, 153, 14, 161, 14, 188, 14, 206, 14, + 219, 14, 250, 15, 25, 15, 43, 15, 58, 15, 78, 15, 109, 15, 123, 15, 131, 15, 141, 15, + 162, 15, 191, 15, 204, 15, 235, 16, 6, 16, 20, 16, 26, 16, 49, 16, 76, 16, 99, 16, 113, + 16, 131, 16, 144, 16, 167, 16, 195, 16, 210, 16, 222, 16, 237, 17, 3, 17, 28, 17, 54, + 17, 80, 17, 93, 17, 107, 17, 136, 17, 143, 17, 152, 17, 178, 17, 200, 17, 224, 17, 243, + 18, 14, 18, 33, 18, 37, 18, 67, 18, 95, 18, 120, 18, 148, 18, 163, 18, 191, 18, 205, + 18, 218, 18, 230, 18, 255, 19, 7, 19, 34, 19, 54, 19, 67, 19, 87, 19, 106, 19, 129, 19, + 175, 19, 200, 19, 218, 19, 223, 19, 232, 19, 242, 20, 15, 20, 20, 20, 40, 20, 59, 20, + 64, 20, 96, 20, 103, 20, 107, 20, 126, 20, 140, 20, 161, 20, 181, 20, 195, 20, 227, 20, + 254, 21, 8, 21, 15, 21, 24, 21, 42, 21, 55, 21, 84, 21, 103, 21, 132, 21, 150, 21, 171, + 21, 219, 21, 227, 21, 246, 22, 5, 22, 33, 22, 53, 22, 68, 22, 90, 22, 117, 22, 146, 22, + 161, 22, 185, 22, 207, 22, 226, 22, 235, 23, 1, 23, 19, 23, 31, 23, 56, 23, 74, 23, 86, + 23, 96, 23, 103, 23, 126, 23, 145, 23, 166, 23, 178, 23, 197, 23, 208, 23, 232, 23, + 237, 24, 20, 24, 53, 24, 82, 24, 106, 24, 119, 24, 146, 24, 173, 24, 183, 24, 213, 24, + 226, 24, 246, 25, 0, 25, 19, 25, 26, 25, 45, 25, 59, 25, 89, 25, 101, 25, 120, 25, 128, + 25, 133, 25, 141, 25, 155, 25, 174, 25, 201, 25, 227, 25, 247, 26, 10, 26, 28, 26, 55, + 26, 58, 26, 60, 26, 62, 26, 65, 26, 67, 26, 69, 26, 71, 26, 74, 26, 77, 26, 80, 26, 83, + 26, 85, 26, 87, 26, 89, 26, 91, 26, 94, 26, 96, 26, 98, 26, 100, 26, 103, 26, 105, 26, + 108, 26, 111, 26, 114, 26, 116, 26, 119, 26, 122, 26, 125, 26, 127, 26, 129, 26, 131, + 26, 134, 26, 137, 26, 139, 26, 142, 26, 145, 26, 147, 26, 150, 26, 153, 26, 156, 26, + 158, 26, 160, 26, 162, 26, 165, 26, 168, 26, 170, 26, 173, 26, 175, 26, 177, 26, 180, + 26, 182, 26, 185, 26, 188, 26, 190, 26, 192, 26, 194, 26, 197, 26, 200, 26, 202, 26, + 205, 26, 207, 26, 210, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 219, + ]; + + let (_, statedump_results) = Statedump::parse_statedump(&test_data).unwrap(); + assert_eq!(statedump_results.chunk_tag, 0x6003); + assert_eq!(statedump_results.chunk_subtag, 0); + assert_eq!(statedump_results.chunk_data_size, 7859); + assert_eq!(statedump_results.first_proc_id, 1771); + assert_eq!(statedump_results.second_proc_id, 1772); + assert_eq!(statedump_results.ttl, 14); + assert_eq!(statedump_results.unknown_reserved, [0, 0, 0]); + assert_eq!(statedump_results.continuous_time, 10048439123292); + assert_eq!(statedump_results.activity_id, 9223372036854833248); + assert_eq!(statedump_results.uuid, "7E5D9855D1CC382DB8EB25A030D4B2FA"); + assert_eq!(statedump_results.unknown_data_type, 1); // plist + assert_eq!(statedump_results.unknown_data_size, 7611); + assert_eq!(statedump_results.unknown_object_type_string_1, ""); + assert_eq!(statedump_results.unknown_object_type_string_2, ""); + assert_eq!(statedump_results.unknown_name, "WebContent state"); + assert_eq!( + statedump_results.statedump_data, + [ + 98, 112, 108, 105, 115, 116, 48, 48, 211, 0, 1, 0, 2, 0, 3, 0, 4, 0, 23, 1, 94, 95, + 16, 18, 77, 101, 109, 111, 114, 121, 32, 85, 115, 97, 103, 101, 32, 83, 116, 97, + 116, 115, 95, 16, 24, 74, 97, 118, 97, 83, 99, 114, 105, 112, 116, 32, 79, 98, 106, + 101, 99, 116, 32, 67, 111, 117, 110, 116, 115, 95, 16, 15, 80, 97, 103, 101, 32, + 76, 111, 97, 100, 32, 84, 105, 109, 101, 115, 217, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, + 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, + 22, 95, 16, 43, 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 95, 103, 99, 95, + 112, 114, 111, 116, 101, 99, 116, 101, 100, 95, 103, 108, 111, 98, 97, 108, 95, + 111, 98, 106, 101, 99, 116, 95, 99, 111, 117, 110, 116, 94, 100, 111, 99, 117, 109, + 101, 110, 116, 95, 99, 111, 117, 110, 116, 95, 16, 23, 106, 97, 118, 97, 115, 99, + 114, 105, 112, 116, 95, 103, 99, 95, 104, 101, 97, 112, 95, 115, 105, 122, 101, 95, + 16, 36, 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 95, 103, 99, 95, 104, 101, + 97, 112, 95, 101, 120, 116, 114, 97, 95, 109, 101, 109, 111, 114, 121, 95, 115, + 105, 122, 101, 95, 16, 33, 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 95, 103, + 99, 95, 103, 108, 111, 98, 97, 108, 95, 111, 98, 106, 101, 99, 116, 95, 99, 111, + 117, 110, 116, 95, 16, 26, 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 95, 103, + 99, 95, 111, 98, 106, 101, 99, 116, 95, 99, 111, 117, 110, 116, 95, 16, 27, 106, + 97, 118, 97, 115, 99, 114, 105, 112, 116, 95, 103, 99, 95, 104, 101, 97, 112, 95, + 99, 97, 112, 97, 99, 105, 116, 121, 95, 16, 36, 106, 97, 118, 97, 115, 99, 114, + 105, 112, 116, 95, 103, 99, 95, 112, 114, 111, 116, 101, 99, 116, 101, 100, 95, + 111, 98, 106, 101, 99, 116, 95, 99, 111, 117, 110, 116, 95, 16, 20, 112, 97, 103, + 101, 99, 97, 99, 104, 101, 95, 112, 97, 103, 101, 95, 99, 111, 117, 110, 116, 16, + 2, 16, 24, 18, 1, 28, 208, 17, 18, 0, 96, 153, 97, 16, 9, 18, 0, 1, 181, 224, 18, + 1, 205, 197, 241, 16, 114, 16, 1, 223, 17, 1, 9, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, + 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, + 0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0, 49, 0, 50, 0, 51, 0, 52, + 0, 53, 0, 54, 0, 55, 0, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64, + 0, 65, 0, 66, 0, 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72, 0, 73, 0, 74, 0, 75, 0, 76, + 0, 77, 0, 78, 0, 79, 0, 80, 0, 81, 0, 82, 0, 83, 0, 84, 0, 85, 0, 86, 0, 87, 0, 88, + 0, 89, 0, 90, 0, 91, 0, 92, 0, 93, 0, 94, 0, 95, 0, 96, 0, 97, 0, 98, 0, 99, 0, + 100, 0, 101, 0, 102, 0, 103, 0, 104, 0, 105, 0, 106, 0, 107, 0, 108, 0, 109, 0, + 110, 0, 111, 0, 112, 0, 113, 0, 114, 0, 115, 0, 116, 0, 117, 0, 118, 0, 119, 0, + 120, 0, 121, 0, 122, 0, 123, 0, 124, 0, 125, 0, 126, 0, 127, 0, 128, 0, 129, 0, + 130, 0, 131, 0, 132, 0, 133, 0, 134, 0, 135, 0, 136, 0, 137, 0, 138, 0, 139, 0, + 140, 0, 141, 0, 142, 0, 143, 0, 144, 0, 145, 0, 146, 0, 147, 0, 148, 0, 149, 0, + 150, 0, 151, 0, 152, 0, 153, 0, 154, 0, 155, 0, 156, 0, 157, 0, 158, 0, 159, 0, + 160, 0, 161, 0, 162, 0, 163, 0, 164, 0, 165, 0, 166, 0, 167, 0, 168, 0, 169, 0, + 170, 0, 171, 0, 172, 0, 173, 0, 174, 0, 175, 0, 176, 0, 177, 0, 178, 0, 179, 0, + 180, 0, 181, 0, 182, 0, 183, 0, 184, 0, 185, 0, 186, 0, 187, 0, 188, 0, 189, 0, + 190, 0, 191, 0, 192, 0, 193, 0, 194, 0, 195, 0, 196, 0, 197, 0, 198, 0, 199, 0, + 200, 0, 201, 0, 202, 0, 203, 0, 204, 0, 205, 0, 206, 0, 207, 0, 208, 0, 209, 0, + 210, 0, 211, 0, 212, 0, 213, 0, 214, 0, 215, 0, 216, 0, 217, 0, 218, 0, 219, 0, + 220, 0, 221, 0, 222, 0, 223, 0, 224, 0, 225, 0, 226, 0, 227, 0, 228, 0, 229, 0, + 230, 0, 231, 0, 232, 0, 233, 0, 234, 0, 235, 0, 236, 0, 237, 0, 238, 0, 239, 0, + 240, 0, 241, 0, 242, 0, 243, 0, 244, 0, 245, 0, 246, 0, 247, 0, 248, 0, 249, 0, + 250, 0, 251, 0, 252, 0, 253, 0, 254, 0, 255, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, + 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, + 1, 19, 1, 20, 1, 21, 1, 22, 1, 23, 1, 24, 1, 25, 1, 26, 1, 27, 1, 28, 1, 29, 1, 30, + 1, 31, 1, 32, 1, 33, 1, 34, 0, 18, 0, 22, 0, 22, 0, 22, 0, 22, 0, 14, 0, 22, 0, 22, + 0, 22, 0, 22, 1, 35, 1, 36, 0, 22, 0, 14, 1, 37, 1, 38, 0, 22, 1, 39, 1, 40, 1, 41, + 1, 42, 1, 43, 0, 22, 0, 14, 1, 44, 0, 22, 1, 45, 0, 22, 1, 46, 0, 18, 0, 22, 0, 22, + 0, 22, 1, 39, 0, 22, 0, 14, 0, 14, 0, 14, 0, 22, 1, 39, 0, 22, 0, 22, 1, 47, 1, 44, + 1, 48, 0, 18, 1, 49, 1, 35, 1, 46, 1, 50, 0, 14, 0, 22, 0, 22, 1, 51, 1, 35, 0, 22, + 1, 52, 0, 22, 1, 35, 1, 46, 0, 18, 1, 44, 1, 53, 1, 47, 1, 39, 0, 18, 0, 22, 0, 18, + 0, 22, 1, 54, 0, 22, 0, 18, 0, 22, 1, 45, 1, 46, 0, 22, 0, 18, 0, 18, 1, 35, 0, 22, + 1, 55, 0, 22, 0, 18, 1, 39, 1, 56, 0, 18, 0, 22, 0, 22, 0, 22, 0, 22, 1, 57, 1, 35, + 0, 22, 1, 46, 1, 58, 0, 14, 0, 18, 1, 59, 0, 14, 0, 14, 1, 46, 0, 14, 0, 14, 0, 14, + 1, 39, 1, 60, 1, 44, 0, 14, 0, 22, 0, 14, 1, 39, 0, 14, 0, 14, 1, 46, 1, 61, 0, 18, + 0, 22, 0, 22, 1, 62, 1, 63, 0, 22, 0, 22, 1, 64, 0, 22, 1, 65, 1, 57, 0, 22, 0, 18, + 1, 39, 1, 66, 1, 67, 0, 18, 0, 18, 0, 22, 1, 68, 1, 45, 1, 69, 0, 14, 1, 70, 0, 22, + 1, 46, 0, 14, 1, 71, 0, 14, 0, 22, 1, 72, 0, 18, 1, 47, 0, 22, 0, 14, 1, 39, 0, 14, + 1, 57, 1, 73, 0, 22, 1, 35, 1, 39, 0, 14, 1, 44, 0, 14, 0, 14, 1, 37, 0, 22, 0, 18, + 0, 22, 0, 18, 1, 47, 1, 74, 1, 73, 1, 35, 1, 57, 1, 46, 0, 14, 1, 75, 0, 14, 0, 22, + 1, 76, 0, 22, 0, 22, 1, 47, 1, 77, 1, 35, 0, 14, 1, 78, 1, 78, 1, 44, 0, 22, 1, 44, + 1, 57, 1, 79, 1, 47, 1, 47, 0, 22, 0, 18, 1, 35, 1, 80, 1, 81, 1, 35, 1, 35, 0, 22, + 0, 22, 0, 14, 1, 46, 0, 14, 1, 45, 0, 14, 0, 22, 0, 14, 1, 82, 1, 57, 1, 83, 0, 14, + 1, 37, 0, 14, 1, 47, 1, 39, 1, 84, 0, 14, 1, 39, 1, 85, 1, 39, 1, 39, 0, 22, 0, 22, + 0, 14, 0, 18, 1, 86, 0, 18, 1, 87, 1, 88, 0, 22, 1, 57, 1, 47, 0, 22, 0, 22, 1, 47, + 1, 44, 0, 18, 0, 18, 1, 39, 0, 22, 0, 22, 0, 18, 1, 89, 1, 35, 0, 18, 1, 90, 0, 18, + 1, 91, 1, 39, 1, 47, 0, 22, 1, 92, 1, 47, 1, 47, 0, 22, 1, 35, 1, 47, 1, 39, 0, 15, + 1, 46, 1, 93, 1, 44, 94, 83, 116, 114, 117, 99, 116, 117, 114, 101, 67, 104, 97, + 105, 110, 95, 16, 18, 72, 84, 77, 76, 72, 101, 97, 100, 105, 110, 103, 69, 108, + 101, 109, 101, 110, 116, 89, 71, 101, 110, 101, 114, 97, 116, 111, 114, 95, 16, 25, + 72, 84, 77, 76, 84, 105, 116, 108, 101, 69, 108, 101, 109, 101, 110, 116, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 95, 16, 20, 85, 105, 110, 116, 49, 54, 65, 114, + 114, 97, 121, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 23, 83, 86, 71, + 68, 101, 102, 115, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 90, 77, 111, 117, 115, 101, 69, 118, 101, 110, 116, 95, 16, 16, 72, + 84, 77, 76, 79, 76, 105, 115, 116, 69, 108, 101, 109, 101, 110, 116, 95, 16, 23, + 77, 117, 116, 97, 116, 105, 111, 110, 82, 101, 99, 111, 114, 100, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 34, 88, 77, 76, 72, 116, 116, 112, 82, 101, + 113, 117, 101, 115, 116, 69, 118, 101, 110, 116, 84, 97, 114, 103, 101, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 92, 68, 111, 99, 117, 109, 101, 110, 116, + 84, 121, 112, 101, 95, 16, 27, 72, 84, 77, 76, 85, 110, 107, 110, 111, 119, 110, + 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, + 16, 25, 72, 84, 77, 76, 84, 97, 98, 108, 101, 69, 108, 101, 109, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 18, 67, 117, 115, 116, 111, 109, + 71, 101, 116, 116, 101, 114, 83, 101, 116, 116, 101, 114, 95, 16, 23, 83, 86, 71, + 80, 97, 116, 104, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 16, 83, 116, 111, 114, 97, 103, 101, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 91, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 93, 65, + 115, 121, 110, 99, 70, 117, 110, 99, 116, 105, 111, 110, 92, 71, 108, 111, 98, 97, + 108, 79, 98, 106, 101, 99, 116, 87, 67, 111, 109, 109, 101, 110, 116, 95, 16, 17, + 83, 116, 114, 117, 99, 116, 117, 114, 101, 82, 97, 114, 101, 68, 97, 116, 97, 95, + 16, 26, 85, 110, 108, 105, 110, 107, 101, 100, 70, 117, 110, 99, 116, 105, 111, + 110, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 93, 72, 97, 115, 104, 77, 97, + 112, 66, 117, 99, 107, 101, 116, 95, 16, 25, 85, 110, 108, 105, 110, 107, 101, 100, + 70, 117, 110, 99, 116, 105, 111, 110, 67, 111, 100, 101, 66, 108, 111, 99, 107, 95, + 16, 16, 72, 84, 77, 76, 84, 105, 116, 108, 101, 69, 108, 101, 109, 101, 110, 116, + 94, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, 95, 16, 20, + 83, 99, 111, 112, 101, 100, 65, 114, 103, 117, 109, 101, 110, 116, 115, 84, 97, 98, + 108, 101, 95, 16, 19, 80, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 79, 98, + 115, 101, 114, 118, 101, 114, 86, 67, 97, 108, 108, 101, 101, 95, 16, 23, 88, 77, + 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 86, 87, 105, 110, 100, 111, 119, 95, 16, 21, 87, 101, 98, 65, + 115, 115, 101, 109, 98, 108, 121, 46, 76, 105, 110, 107, 69, 114, 114, 111, 114, + 92, 67, 83, 83, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 28, 72, 84, 77, + 76, 70, 105, 101, 108, 100, 83, 101, 116, 69, 108, 101, 109, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 17, 68, 79, 77, 73, 109, 112, 108, + 101, 109, 101, 110, 116, 97, 116, 105, 111, 110, 95, 16, 25, 72, 84, 77, 76, 85, + 76, 105, 115, 116, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 26, 72, 84, 77, 76, 83, 101, 108, 101, 99, 116, 69, 108, + 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 28, + 72, 84, 77, 76, 84, 97, 98, 108, 101, 82, 111, 119, 69, 108, 101, 109, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 16, 68, 111, 99, 117, 109, + 101, 110, 116, 70, 114, 97, 103, 109, 101, 110, 116, 95, 16, 19, 83, 86, 71, 69, + 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 85, 69, + 118, 101, 110, 116, 87, 74, 83, 80, 114, 111, 120, 121, 95, 16, 21, 68, 111, 99, + 117, 109, 101, 110, 116, 84, 121, 112, 101, 80, 114, 111, 116, 111, 116, 121, 112, + 101, 95, 16, 24, 72, 84, 77, 76, 76, 105, 110, 107, 69, 108, 101, 109, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 28, 67, 83, 83, 83, 116, + 121, 108, 101, 68, 101, 99, 108, 97, 114, 97, 116, 105, 111, 110, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 25, 72, 84, 77, 76, 73, 109, 97, 103, 101, + 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, + 115, 116, 114, 105, 110, 103, 95, 16, 18, 87, 101, 98, 65, 115, 115, 101, 109, 98, + 108, 121, 46, 77, 111, 100, 117, 108, 101, 87, 80, 114, 111, 109, 105, 115, 101, + 92, 68, 79, 77, 69, 120, 99, 101, 112, 116, 105, 111, 110, 95, 16, 17, 83, 86, 71, + 65, 110, 105, 109, 97, 116, 101, 100, 83, 116, 114, 105, 110, 103, 95, 16, 24, 85, + 110, 108, 105, 110, 107, 101, 100, 80, 114, 111, 103, 114, 97, 109, 67, 111, 100, + 101, 66, 108, 111, 99, 107, 95, 16, 15, 67, 114, 121, 112, 116, 111, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 30, 67, 117, 115, 116, 111, 109, 69, 108, + 101, 109, 101, 110, 116, 82, 101, 103, 105, 115, 116, 114, 121, 80, 114, 111, 116, + 111, 116, 121, 112, 101, 94, 69, 118, 97, 108, 69, 120, 101, 99, 117, 116, 97, 98, + 108, 101, 86, 83, 116, 114, 105, 110, 103, 95, 16, 32, 72, 84, 77, 76, 84, 97, 98, + 108, 101, 83, 101, 99, 116, 105, 111, 110, 69, 108, 101, 109, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 83, 67, 83, 83, 95, 16, 18, 70, 117, 110, + 99, 116, 105, 111, 110, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 95, 16, 21, + 68, 79, 77, 69, 120, 99, 101, 112, 116, 105, 111, 110, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 16, 80, 114, 111, 103, 114, 97, 109, 67, 111, 100, 101, 66, + 108, 111, 99, 107, 95, 16, 42, 82, 101, 97, 100, 97, 98, 108, 101, 83, 116, 114, + 101, 97, 109, 66, 89, 79, 66, 82, 101, 97, 100, 101, 114, 80, 114, 105, 118, 97, + 116, 101, 67, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 93, 65, 115, 121, + 110, 99, 73, 116, 101, 114, 97, 116, 111, 114, 94, 83, 86, 71, 80, 97, 116, 104, + 69, 108, 101, 109, 101, 110, 116, 95, 16, 16, 70, 117, 110, 99, 116, 105, 111, 110, + 82, 97, 114, 101, 68, 97, 116, 97, 95, 16, 24, 72, 84, 77, 76, 66, 111, 100, 121, + 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, + 16, 19, 83, 112, 97, 114, 115, 101, 65, 114, 114, 97, 121, 86, 97, 108, 117, 101, + 77, 97, 112, 95, 16, 21, 65, 115, 121, 110, 99, 70, 114, 111, 109, 83, 121, 110, + 99, 73, 116, 101, 114, 97, 116, 111, 114, 90, 84, 114, 101, 101, 87, 97, 108, 107, + 101, 114, 95, 16, 24, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, 82, + 117, 110, 116, 105, 109, 101, 69, 114, 114, 111, 114, 95, 16, 15, 72, 84, 77, 76, + 66, 97, 115, 101, 69, 108, 101, 109, 101, 110, 116, 88, 78, 111, 100, 101, 76, 105, + 115, 116, 89, 78, 97, 118, 105, 103, 97, 116, 111, 114, 95, 16, 26, 74, 83, 71, + 108, 111, 98, 97, 108, 76, 101, 120, 105, 99, 97, 108, 69, 110, 118, 105, 114, 111, + 110, 109, 101, 110, 116, 95, 16, 24, 85, 82, 76, 83, 101, 97, 114, 99, 104, 80, 97, + 114, 97, 109, 115, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 16, 72, 84, + 77, 76, 73, 110, 112, 117, 116, 69, 108, 101, 109, 101, 110, 116, 95, 16, 20, 69, + 118, 101, 110, 116, 84, 97, 114, 103, 101, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 18, 72, 84, 77, 76, 68, 101, 116, 97, 105, 108, 115, 69, 108, + 101, 109, 101, 110, 116, 95, 16, 24, 73, 110, 115, 112, 101, 99, 116, 111, 114, 73, + 110, 115, 116, 114, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 87, 66, 111, + 111, 108, 101, 97, 110, 95, 16, 25, 72, 84, 77, 76, 73, 110, 112, 117, 116, 69, + 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, + 20, 68, 79, 77, 82, 101, 99, 116, 76, 105, 115, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 20, 74, 83, 76, 101, 120, 105, 99, 97, 108, 69, 110, 118, + 105, 114, 111, 110, 109, 101, 110, 116, 95, 16, 25, 77, 117, 116, 97, 116, 105, + 111, 110, 79, 98, 115, 101, 114, 118, 101, 114, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 94, 65, 114, 114, 97, 121, 32, 73, 116, 101, 114, 97, 116, 111, 114, 93, + 84, 101, 120, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 17, 73, 110, + 102, 101, 114, 114, 101, 100, 84, 121, 112, 101, 84, 97, 98, 108, 101, 95, 16, 20, + 72, 84, 77, 76, 84, 97, 98, 108, 101, 67, 101, 108, 108, 69, 108, 101, 109, 101, + 110, 116, 95, 16, 15, 68, 79, 77, 82, 101, 99, 116, 82, 101, 97, 100, 79, 110, 108, + 121, 95, 16, 27, 83, 86, 71, 67, 108, 105, 112, 80, 97, 116, 104, 69, 108, 101, + 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 18, 87, + 101, 98, 83, 111, 99, 107, 101, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 94, 83, 86, 71, 68, 101, 102, 115, 69, 108, 101, 109, 101, 110, 116, 85, 82, 97, + 110, 103, 101, 95, 16, 17, 80, 114, 111, 103, 114, 97, 109, 69, 120, 101, 99, 117, + 116, 97, 98, 108, 101, 87, 67, 111, 110, 115, 111, 108, 101, 95, 16, 49, 82, 101, + 97, 100, 97, 98, 108, 101, 83, 116, 114, 101, 97, 109, 68, 101, 102, 97, 117, 108, + 116, 67, 111, 110, 116, 114, 111, 108, 108, 101, 114, 80, 114, 105, 118, 97, 116, + 101, 67, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 95, 16, 17, 72, 84, 77, + 76, 65, 110, 99, 104, 111, 114, 69, 108, 101, 109, 101, 110, 116, 95, 16, 16, 85, + 73, 69, 118, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 78, + 117, 109, 98, 101, 114, 84, 84, 101, 120, 116, 95, 16, 19, 80, 97, 103, 101, 84, + 114, 97, 110, 115, 105, 116, 105, 111, 110, 69, 118, 101, 110, 116, 95, 16, 25, 72, + 84, 77, 76, 76, 97, 98, 101, 108, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 46, 82, 101, 97, 100, 97, 98, 108, 101, 66, + 121, 116, 101, 83, 116, 114, 101, 97, 109, 67, 111, 110, 116, 114, 111, 108, 108, + 101, 114, 80, 114, 105, 118, 97, 116, 101, 67, 111, 110, 115, 116, 114, 117, 99, + 116, 111, 114, 95, 16, 27, 83, 86, 71, 71, 114, 97, 112, 104, 105, 99, 115, 69, + 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, + 19, 77, 111, 117, 115, 101, 69, 118, 101, 110, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 22, 83, 86, 71, 83, 86, 71, 69, 108, 101, 109, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 15, 72, 84, 77, 76, 72, + 101, 97, 100, 69, 108, 101, 109, 101, 110, 116, 85, 65, 114, 114, 97, 121, 95, 16, + 20, 88, 80, 97, 116, 104, 82, 101, 115, 117, 108, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 87, 83, 116, 111, 114, 97, 103, 101, 95, 16, 24, 72, 84, 77, 76, 66, + 97, 115, 101, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 15, 72, 84, 77, 76, 70, 111, 114, 109, 69, 108, 101, 109, 101, + 110, 116, 92, 78, 97, 109, 101, 100, 78, 111, 100, 101, 77, 97, 112, 95, 16, 28, + 80, 97, 103, 101, 84, 114, 97, 110, 115, 105, 116, 105, 111, 110, 69, 118, 101, + 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 28, 72, 84, 77, 76, + 84, 101, 109, 112, 108, 97, 116, 101, 69, 108, 101, 109, 101, 110, 116, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 95, 16, 15, 87, 105, 110, 100, 111, 119, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 94, 72, 84, 77, 76, 67, 111, 108, 108, 101, + 99, 116, 105, 111, 110, 95, 16, 17, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, + 121, 46, 84, 97, 98, 108, 101, 95, 16, 28, 72, 84, 77, 76, 84, 101, 120, 116, 65, + 114, 101, 97, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 93, 65, 116, 116, 114, 80, 114, 111, 116, 111, 116, 121, 112, 101, 87, + 87, 101, 97, 107, 77, 97, 112, 89, 65, 114, 103, 117, 109, 101, 110, 116, 115, 95, + 16, 18, 68, 79, 77, 80, 97, 114, 115, 101, 114, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 26, 80, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 84, 105, + 109, 105, 110, 103, 80, 114, 111, 116, 111, 116, 121, 112, 101, 92, 73, 110, 102, + 101, 114, 114, 101, 100, 84, 121, 112, 101, 95, 16, 28, 80, 101, 114, 102, 111, + 114, 109, 97, 110, 99, 101, 79, 98, 115, 101, 114, 118, 101, 114, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 95, 16, 24, 68, 79, 77, 65, 116, 116, 114, 105, 98, + 117, 116, 101, 71, 101, 116, 116, 101, 114, 83, 101, 116, 116, 101, 114, 93, 78, + 111, 100, 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 85, 69, 114, 114, 111, + 114, 95, 16, 20, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, 73, 110, + 115, 116, 97, 110, 99, 101, 95, 16, 24, 72, 84, 77, 76, 83, 112, 97, 110, 69, 108, + 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 20, + 72, 84, 77, 76, 80, 97, 114, 97, 103, 114, 97, 112, 104, 69, 108, 101, 109, 101, + 110, 116, 93, 80, 114, 111, 112, 101, 114, 116, 121, 84, 97, 98, 108, 101, 95, 16, + 15, 83, 116, 114, 105, 110, 103, 32, 73, 116, 101, 114, 97, 116, 111, 114, 92, 72, + 84, 77, 76, 68, 111, 99, 117, 109, 101, 110, 116, 95, 16, 20, 80, 101, 114, 102, + 111, 114, 109, 97, 110, 99, 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, + 16, 25, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 84, 111, 67, 111, 100, 101, + 66, 108, 111, 99, 107, 69, 100, 103, 101, 94, 67, 97, 108, 108, 98, 97, 99, 107, + 79, 98, 106, 101, 99, 116, 91, 72, 84, 77, 76, 69, 108, 101, 109, 101, 110, 116, + 94, 69, 118, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 19, + 67, 83, 83, 83, 116, 121, 108, 101, 68, 101, 99, 108, 97, 114, 97, 116, 105, 111, + 110, 95, 16, 22, 80, 114, 111, 103, 114, 101, 115, 115, 69, 118, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 23, 72, 84, 77, 76, 84, 97, 98, + 108, 101, 83, 101, 99, 116, 105, 111, 110, 69, 108, 101, 109, 101, 110, 116, 95, + 16, 23, 72, 84, 77, 76, 80, 114, 101, 69, 108, 101, 109, 101, 110, 116, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 92, 74, 83, 70, 105, 120, 101, 100, 65, 114, + 114, 97, 121, 93, 83, 86, 71, 83, 86, 71, 69, 108, 101, 109, 101, 110, 116, 95, 16, + 26, 68, 79, 77, 73, 109, 112, 108, 101, 109, 101, 110, 116, 97, 116, 105, 111, 110, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 82, 101, 103, 69, 120, 112, 88, 73, + 116, 101, 114, 97, 116, 111, 114, 95, 16, 23, 72, 84, 77, 76, 68, 105, 118, 69, + 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, + 19, 84, 114, 101, 101, 87, 97, 108, 107, 101, 114, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 21, 85, 110, 108, 105, 110, 107, 101, 100, 69, 118, 97, 108, + 67, 111, 100, 101, 66, 108, 111, 99, 107, 95, 16, 16, 68, 79, 77, 82, 101, 99, 116, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 24, 72, 84, 77, 76, 70, 111, + 114, 109, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, + 101, 95, 16, 16, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 83, 77, 97, 112, 95, 16, 27, 72, 84, 77, 76, 68, 101, 116, 97, 105, + 108, 115, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, + 101, 95, 16, 25, 72, 84, 77, 76, 83, 116, 121, 108, 101, 69, 108, 101, 109, 101, + 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 22, 67, 104, 97, 114, + 97, 99, 116, 101, 114, 68, 97, 116, 97, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 95, 16, 25, 68, 111, 99, 117, 109, 101, 110, 116, 70, 114, 97, 103, 109, 101, 110, + 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 94, 72, 84, 77, 76, 80, 114, 101, + 69, 108, 101, 109, 101, 110, 116, 95, 16, 25, 72, 84, 77, 76, 79, 76, 105, 115, + 116, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 93, 72, 84, 77, 76, 66, 82, 69, 108, 101, 109, 101, 110, 116, 92, 77, 111, 100, + 117, 108, 101, 76, 111, 97, 100, 101, 114, 91, 68, 79, 77, 82, 101, 99, 116, 76, + 105, 115, 116, 95, 16, 22, 65, 115, 121, 110, 99, 71, 101, 110, 101, 114, 97, 116, + 111, 114, 70, 117, 110, 99, 116, 105, 111, 110, 87, 72, 105, 115, 116, 111, 114, + 121, 95, 16, 24, 73, 110, 116, 101, 114, 110, 97, 108, 80, 114, 111, 109, 105, 115, + 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 17, 78, 111, 100, 101, 76, + 105, 115, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 92, 71, 101, 116, 116, + 101, 114, 83, 101, 116, 116, 101, 114, 95, 16, 17, 71, 101, 110, 101, 114, 97, 116, + 111, 114, 70, 117, 110, 99, 116, 105, 111, 110, 95, 16, 16, 67, 111, 109, 109, 101, + 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 20, 72, 84, 77, 76, + 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, + 16, 43, 82, 101, 97, 100, 97, 98, 108, 101, 83, 116, 114, 101, 97, 109, 66, 89, 79, + 66, 82, 101, 113, 117, 101, 115, 116, 80, 114, 105, 118, 97, 116, 101, 67, 111, + 110, 115, 116, 114, 117, 99, 116, 111, 114, 95, 16, 22, 72, 84, 77, 76, 66, 82, 69, + 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, + 15, 72, 84, 77, 76, 77, 101, 116, 97, 69, 108, 101, 109, 101, 110, 116, 84, 65, + 116, 116, 114, 88, 68, 111, 99, 117, 109, 101, 110, 116, 89, 83, 116, 114, 117, 99, + 116, 117, 114, 101, 95, 16, 26, 83, 86, 71, 65, 110, 105, 109, 97, 116, 101, 100, + 83, 116, 114, 105, 110, 103, 80, 114, 111, 116, 111, 116, 121, 112, 101, 84, 66, + 108, 111, 98, 95, 16, 17, 76, 111, 99, 97, 116, 105, 111, 110, 80, 114, 111, 116, + 111, 116, 121, 112, 101, 95, 16, 16, 78, 97, 116, 105, 118, 101, 69, 120, 101, 99, + 117, 116, 97, 98, 108, 101, 84, 74, 83, 79, 78, 95, 16, 29, 72, 84, 77, 76, 84, 97, + 98, 108, 101, 67, 101, 108, 108, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, + 116, 111, 116, 121, 112, 101, 86, 115, 121, 109, 98, 111, 108, 83, 83, 101, 116, + 95, 16, 16, 67, 97, 108, 108, 98, 97, 99, 107, 70, 117, 110, 99, 116, 105, 111, + 110, 93, 66, 108, 111, 98, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 18, + 83, 86, 71, 67, 108, 105, 112, 80, 97, 116, 104, 69, 108, 101, 109, 101, 110, 116, + 95, 16, 17, 68, 111, 99, 117, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 93, 73, 110, 102, 101, 114, 114, 101, 100, 86, 97, 108, 117, 101, 95, 16, + 29, 72, 84, 77, 76, 80, 97, 114, 97, 103, 114, 97, 112, 104, 69, 108, 101, 109, + 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 24, 72, 84, 77, + 76, 77, 101, 116, 97, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, + 116, 121, 112, 101, 89, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 83, 121, + 109, 98, 111, 108, 88, 76, 111, 99, 97, 116, 105, 111, 110, 95, 16, 15, 72, 84, 77, + 76, 76, 105, 110, 107, 69, 108, 101, 109, 101, 110, 116, 92, 68, 79, 77, 84, 111, + 107, 101, 110, 76, 105, 115, 116, 95, 16, 26, 72, 84, 77, 76, 83, 99, 114, 105, + 112, 116, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, + 101, 95, 16, 16, 77, 117, 116, 97, 116, 105, 111, 110, 79, 98, 115, 101, 114, 118, + 101, 114, 95, 16, 26, 72, 84, 77, 76, 79, 112, 116, 105, 111, 110, 69, 108, 101, + 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 15, 85, 82, + 76, 83, 101, 97, 114, 99, 104, 80, 97, 114, 97, 109, 115, 95, 16, 18, 78, 97, 118, + 105, 103, 97, 116, 111, 114, 80, 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, + 45, 82, 101, 97, 100, 97, 98, 108, 101, 83, 116, 114, 101, 97, 109, 68, 101, 102, + 97, 117, 108, 116, 82, 101, 97, 100, 101, 114, 80, 114, 105, 118, 97, 116, 101, 67, + 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 87, 87, 101, 97, 107, 83, 101, + 116, 95, 16, 16, 72, 84, 77, 76, 83, 116, 121, 108, 101, 69, 108, 101, 109, 101, + 110, 116, 94, 82, 97, 110, 103, 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 95, 16, 25, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, 69, + 118, 101, 110, 116, 84, 97, 114, 103, 101, 116, 95, 16, 17, 72, 84, 77, 76, 66, + 117, 116, 116, 111, 110, 69, 108, 101, 109, 101, 110, 116, 94, 72, 84, 77, 76, 68, + 105, 118, 69, 108, 101, 109, 101, 110, 116, 95, 16, 19, 72, 84, 77, 76, 70, 105, + 101, 108, 100, 83, 101, 116, 69, 108, 101, 109, 101, 110, 116, 95, 16, 24, 74, 83, + 80, 114, 111, 112, 101, 114, 116, 121, 78, 97, 109, 101, 69, 110, 117, 109, 101, + 114, 97, 116, 111, 114, 95, 16, 26, 72, 84, 77, 76, 66, 117, 116, 116, 111, 110, + 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 94, + 65, 115, 121, 110, 99, 71, 101, 110, 101, 114, 97, 116, 111, 114, 95, 16, 21, 78, + 97, 109, 101, 100, 78, 111, 100, 101, 77, 97, 112, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 95, 16, 19, 72, 84, 77, 76, 84, 97, 98, 108, 101, 82, 111, 119, 69, + 108, 101, 109, 101, 110, 116, 95, 16, 16, 74, 83, 68, 79, 77, 87, 105, 110, 100, + 111, 119, 80, 114, 111, 120, 121, 88, 70, 117, 110, 99, 116, 105, 111, 110, 95, 16, + 19, 72, 84, 77, 76, 84, 101, 109, 112, 108, 97, 116, 101, 69, 108, 101, 109, 101, + 110, 116, 95, 16, 15, 72, 84, 77, 76, 66, 111, 100, 121, 69, 108, 101, 109, 101, + 110, 116, 91, 83, 121, 109, 98, 111, 108, 84, 97, 98, 108, 101, 95, 16, 22, 72, 84, + 77, 76, 76, 73, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, + 112, 101, 95, 16, 15, 72, 84, 77, 76, 72, 116, 109, 108, 69, 108, 101, 109, 101, + 110, 116, 91, 80, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 89, 87, 101, 98, + 83, 111, 99, 107, 101, 116, 86, 67, 114, 121, 112, 116, 111, 95, 16, 20, 65, 114, + 114, 97, 121, 66, 117, 102, 102, 101, 114, 80, 114, 111, 116, 111, 116, 121, 112, + 101, 95, 16, 16, 72, 84, 77, 76, 85, 76, 105, 115, 116, 69, 108, 101, 109, 101, + 110, 116, 95, 16, 18, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, 77, + 101, 109, 111, 114, 121, 91, 88, 80, 97, 116, 104, 82, 101, 115, 117, 108, 116, 95, + 16, 16, 72, 84, 77, 76, 73, 109, 97, 103, 101, 69, 108, 101, 109, 101, 110, 116, + 90, 78, 111, 100, 101, 70, 105, 108, 116, 101, 114, 95, 16, 21, 72, 84, 77, 76, 68, + 111, 99, 117, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 84, + 77, 97, 116, 104, 95, 16, 36, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, + 101, 115, 116, 80, 114, 111, 103, 114, 101, 115, 115, 69, 118, 101, 110, 116, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 30, 80, 114, 111, 109, 105, 115, + 101, 82, 101, 106, 101, 99, 116, 105, 111, 110, 69, 118, 101, 110, 116, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 95, 16, 26, 72, 84, 77, 76, 65, 110, 99, 104, + 111, 114, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, + 101, 95, 16, 21, 68, 79, 77, 84, 111, 107, 101, 110, 76, 105, 115, 116, 80, 114, + 111, 116, 111, 116, 121, 112, 101, 92, 77, 97, 112, 32, 73, 116, 101, 114, 97, 116, + 111, 114, 95, 16, 24, 87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121, 46, 67, + 111, 109, 112, 105, 108, 101, 69, 114, 114, 111, 114, 95, 16, 24, 68, 79, 77, 82, + 101, 99, 116, 82, 101, 97, 100, 79, 110, 108, 121, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 89, 68, 79, 77, 80, 97, 114, 115, 101, 114, 95, 16, 27, 88, 77, 76, + 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, 80, 114, 111, 103, 114, 101, + 115, 115, 69, 118, 101, 110, 116, 92, 83, 101, 116, 32, 73, 116, 101, 114, 97, 116, + 111, 114, 95, 16, 17, 70, 117, 110, 99, 116, 105, 111, 110, 67, 111, 100, 101, 66, + 108, 111, 99, 107, 89, 69, 120, 99, 101, 112, 116, 105, 111, 110, 95, 16, 16, 80, + 114, 111, 109, 105, 115, 101, 80, 114, 111, 116, 111, 116, 121, 112, 101, 86, 79, + 98, 106, 101, 99, 116, 95, 16, 16, 72, 84, 77, 76, 84, 97, 98, 108, 101, 69, 108, + 101, 109, 101, 110, 116, 93, 72, 84, 77, 76, 76, 73, 69, 108, 101, 109, 101, 110, + 116, 95, 16, 27, 72, 84, 77, 76, 72, 101, 97, 100, 105, 110, 103, 69, 108, 101, + 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, 91, 69, 118, 101, + 110, 116, 84, 97, 114, 103, 101, 116, 95, 16, 16, 72, 105, 115, 116, 111, 114, 121, + 80, 114, 111, 116, 111, 116, 121, 112, 101, 87, 68, 79, 77, 82, 101, 99, 116, 84, + 78, 111, 100, 101, 87, 69, 108, 101, 109, 101, 110, 116, 93, 69, 118, 97, 108, 67, + 111, 100, 101, 66, 108, 111, 99, 107, 95, 16, 16, 72, 84, 77, 76, 76, 97, 98, 101, + 108, 69, 108, 101, 109, 101, 110, 116, 95, 16, 24, 72, 84, 77, 76, 72, 116, 109, + 108, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, 121, 112, 101, + 95, 16, 23, 72, 84, 77, 76, 67, 111, 108, 108, 101, 99, 116, 105, 111, 110, 80, + 114, 111, 116, 111, 116, 121, 112, 101, 95, 16, 17, 72, 84, 77, 76, 83, 99, 114, + 105, 112, 116, 69, 108, 101, 109, 101, 110, 116, 95, 16, 16, 87, 105, 110, 100, + 111, 119, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 95, 16, 15, 72, 84, 77, + 76, 83, 112, 97, 110, 69, 108, 101, 109, 101, 110, 116, 95, 16, 24, 72, 84, 77, 76, + 72, 101, 97, 100, 69, 108, 101, 109, 101, 110, 116, 80, 114, 111, 116, 111, 116, + 121, 112, 101, 17, 1, 28, 16, 78, 16, 3, 17, 3, 31, 16, 18, 16, 39, 16, 5, 17, 2, + 239, 17, 79, 93, 17, 1, 46, 17, 22, 193, 16, 4, 16, 12, 16, 8, 16, 6, 17, 125, 241, + 16, 29, 16, 77, 16, 15, 17, 21, 197, 16, 132, 17, 1, 24, 17, 4, 197, 17, 2, 158, + 16, 7, 17, 1, 77, 17, 2, 169, 17, 19, 171, 16, 98, 16, 30, 16, 108, 17, 20, 14, 17, + 13, 246, 16, 89, 17, 6, 174, 17, 5, 78, 16, 118, 17, 3, 79, 17, 13, 22, 17, 7, 160, + 16, 22, 16, 224, 16, 14, 17, 35, 209, 17, 2, 125, 16, 13, 17, 28, 63, 16, 20, 16, + 202, 17, 1, 95, 16, 174, 17, 42, 222, 17, 6, 122, 16, 37, 16, 41, 16, 19, 17, 5, + 73, 17, 25, 87, 16, 128, 17, 3, 103, 16, 157, 161, 1, 95, 51, 65, 195, 217, 198, + 124, 0, 194, 240, 0, 8, 0, 21, 0, 42, 0, 69, 0, 87, 0, 124, 0, 170, 0, 185, 0, 211, + 0, 250, 1, 30, 1, 59, 1, 89, 1, 128, 1, 151, 1, 153, 1, 155, 1, 160, 1, 165, 1, + 167, 1, 172, 1, 177, 1, 179, 1, 181, 5, 221, 5, 236, 6, 1, 6, 11, 6, 39, 6, 62, 6, + 88, 6, 99, 6, 118, 6, 144, 6, 181, 6, 194, 6, 224, 6, 252, 7, 17, 7, 43, 7, 62, 7, + 74, 7, 88, 7, 101, 7, 109, 7, 129, 7, 158, 7, 172, 7, 200, 7, 219, 7, 234, 8, 1, 8, + 23, 8, 30, 8, 56, 8, 63, 8, 87, 8, 100, 8, 131, 8, 151, 8, 179, 8, 208, 8, 239, 9, + 2, 9, 24, 9, 30, 9, 38, 9, 62, 9, 89, 9, 120, 9, 148, 9, 155, 9, 176, 9, 184, 9, + 197, 9, 217, 9, 244, 10, 6, 10, 39, 10, 54, 10, 61, 10, 96, 10, 100, 10, 121, 10, + 145, 10, 164, 10, 209, 10, 223, 10, 238, 11, 1, 11, 28, 11, 50, 11, 74, 11, 85, 11, + 112, 11, 130, 11, 139, 11, 149, 11, 178, 11, 205, 11, 224, 11, 247, 12, 12, 12, 39, + 12, 47, 12, 75, 12, 98, 12, 121, 12, 149, 12, 164, 12, 178, 12, 198, 12, 221, 12, + 239, 13, 13, 13, 34, 13, 49, 13, 55, 13, 75, 13, 83, 13, 135, 13, 155, 13, 174, 13, + 181, 13, 186, 13, 208, 13, 236, 14, 29, 14, 59, 14, 81, 14, 106, 14, 124, 14, 130, + 14, 153, 14, 161, 14, 188, 14, 206, 14, 219, 14, 250, 15, 25, 15, 43, 15, 58, 15, + 78, 15, 109, 15, 123, 15, 131, 15, 141, 15, 162, 15, 191, 15, 204, 15, 235, 16, 6, + 16, 20, 16, 26, 16, 49, 16, 76, 16, 99, 16, 113, 16, 131, 16, 144, 16, 167, 16, + 195, 16, 210, 16, 222, 16, 237, 17, 3, 17, 28, 17, 54, 17, 80, 17, 93, 17, 107, 17, + 136, 17, 143, 17, 152, 17, 178, 17, 200, 17, 224, 17, 243, 18, 14, 18, 33, 18, 37, + 18, 67, 18, 95, 18, 120, 18, 148, 18, 163, 18, 191, 18, 205, 18, 218, 18, 230, 18, + 255, 19, 7, 19, 34, 19, 54, 19, 67, 19, 87, 19, 106, 19, 129, 19, 175, 19, 200, 19, + 218, 19, 223, 19, 232, 19, 242, 20, 15, 20, 20, 20, 40, 20, 59, 20, 64, 20, 96, 20, + 103, 20, 107, 20, 126, 20, 140, 20, 161, 20, 181, 20, 195, 20, 227, 20, 254, 21, 8, + 21, 15, 21, 24, 21, 42, 21, 55, 21, 84, 21, 103, 21, 132, 21, 150, 21, 171, 21, + 219, 21, 227, 21, 246, 22, 5, 22, 33, 22, 53, 22, 68, 22, 90, 22, 117, 22, 146, 22, + 161, 22, 185, 22, 207, 22, 226, 22, 235, 23, 1, 23, 19, 23, 31, 23, 56, 23, 74, 23, + 86, 23, 96, 23, 103, 23, 126, 23, 145, 23, 166, 23, 178, 23, 197, 23, 208, 23, 232, + 23, 237, 24, 20, 24, 53, 24, 82, 24, 106, 24, 119, 24, 146, 24, 173, 24, 183, 24, + 213, 24, 226, 24, 246, 25, 0, 25, 19, 25, 26, 25, 45, 25, 59, 25, 89, 25, 101, 25, + 120, 25, 128, 25, 133, 25, 141, 25, 155, 25, 174, 25, 201, 25, 227, 25, 247, 26, + 10, 26, 28, 26, 55, 26, 58, 26, 60, 26, 62, 26, 65, 26, 67, 26, 69, 26, 71, 26, 74, + 26, 77, 26, 80, 26, 83, 26, 85, 26, 87, 26, 89, 26, 91, 26, 94, 26, 96, 26, 98, 26, + 100, 26, 103, 26, 105, 26, 108, 26, 111, 26, 114, 26, 116, 26, 119, 26, 122, 26, + 125, 26, 127, 26, 129, 26, 131, 26, 134, 26, 137, 26, 139, 26, 142, 26, 145, 26, + 147, 26, 150, 26, 153, 26, 156, 26, 158, 26, 160, 26, 162, 26, 165, 26, 168, 26, + 170, 26, 173, 26, 175, 26, 177, 26, 180, 26, 182, 26, 185, 26, 188, 26, 190, 26, + 192, 26, 194, 26, 197, 26, 200, 26, 202, 26, 205, 26, 207, 26, 210, 0, 0, 0, 0, 0, + 0, 2, 2, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, + 219 + ] + ); + } +} diff --git a/src/chunkset.rs b/src/chunkset.rs new file mode 100755 index 0000000..aeef501 --- /dev/null +++ b/src/chunkset.rs @@ -0,0 +1,2465 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use std::mem::size_of; + +use log::{error, warn}; +use lz4_flex::decompress; +use nom::{ + bytes::complete::take, + number::complete::{le_u32, le_u64}, + Needed, +}; + +use crate::chunks::firehose::firehose_log::FirehosePreamble; +use crate::chunks::simpledump::SimpleDump; +use crate::chunks::statedump::Statedump; +use crate::util::padding_size; +use crate::{ + chunks::oversize::Oversize, preamble::LogPreamble, unified_log::UnifiedLogCatalogData, +}; + +#[derive(Debug)] +pub struct ChunksetChunk { + pub chunk_tag: u32, + pub chunk_sub_tag: u32, + pub chunk_data_size: u64, + pub signature: u32, // should be "bv41" + pub uncompress_size: u32, + pub block_size: u32, + pub decompressed_data: Vec, + pub footer: u32, // should be "bv4$" +} + +impl ChunksetChunk { + /// Parse the Chunkset data that contains the actual log entries + pub fn parse_chunkset(data: &[u8]) -> nom::IResult<&[u8], ChunksetChunk> { + let mut chunkset_chunk = ChunksetChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + signature: 0, + uncompress_size: 0, + block_size: 0, + decompressed_data: Vec::new(), + footer: 0, + }; + + let (input, chunk_tag) = take(size_of::())(data)?; + let (input, chunk_sub_tag) = take(size_of::())(input)?; + let (input, chunk_data_size) = take(size_of::())(input)?; + let (input, signature) = take(size_of::())(input)?; + let (input, uncompress_size) = take(size_of::())(input)?; + + let (_, chunkset_chunk_tag) = le_u32(chunk_tag)?; + let (_, chunkset_chunk_sub_tag) = le_u32(chunk_sub_tag)?; + let (_, chunkset_chunk_data_size) = le_u64(chunk_data_size)?; + let (_, chunkset_sig) = le_u32(signature)?; + let (_, chunkset_uncompress_size) = le_u32(uncompress_size)?; + + let bv41 = 825521762; // bv41 signature + let bv41_uncompressed = 758412898; // bv41- signature + + // Data is already decompressed (Observed in tracev3 files in /var/db/diagnostics/Special) + if chunkset_sig == bv41_uncompressed { + let (input, uncompressed_data) = take(chunkset_uncompress_size)(input)?; + chunkset_chunk.decompressed_data = uncompressed_data.to_vec(); + let (input, footer) = take(size_of::())(input)?; + let (_, chunkset_footer) = le_u32(footer)?; + chunkset_chunk.footer = chunkset_footer; + return Ok((input, chunkset_chunk)); + } + + // Compressed data signatue should be bv41 + if chunkset_sig != bv41 { + error!( + "[macos-unifiedlogs] Incorrect compression signature expected bv41, got: {:?}", + chunkset_sig + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + + let (input, block_size) = take(size_of::())(input)?; + let (_, chunkset_block_size) = le_u32(block_size)?; + + chunkset_chunk.chunk_tag = chunkset_chunk_tag; + chunkset_chunk.chunk_sub_tag = chunkset_chunk_sub_tag; + chunkset_chunk.chunk_data_size = chunkset_chunk_data_size; + chunkset_chunk.signature = chunkset_sig; + chunkset_chunk.uncompress_size = chunkset_uncompress_size; + chunkset_chunk.block_size = chunkset_block_size; + + let (input, compressed_data) = take(chunkset_block_size)(input)?; + let decompress_data_results = + decompress(compressed_data, chunkset_uncompress_size as usize); + + // The decompressed data contains multiple log entries + match decompress_data_results { + Ok(decompress_data) => chunkset_chunk.decompressed_data = decompress_data, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to decompress log data: {:?}", + err + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + } + + let (input, footer) = take(size_of::())(input)?; + let (_, chunkset_footer) = le_u32(footer)?; + chunkset_chunk.footer = chunkset_footer; + + Ok((input, chunkset_chunk)) + } + + /// Parse each log (chunk) in the decompressed Chunkset data + pub fn parse_chunkset_data<'a>( + data: &'a [u8], + unified_log_data: &mut UnifiedLogCatalogData, + ) -> nom::IResult<&'a [u8], ()> { + let mut input = data; + let chunk_preamble_size = 16; // Include preamble size in total chunk size + + // Loop through decompressed chunkset data until all log entries (chunks) are read + while !input.is_empty() { + let (_, preamble) = LogPreamble::detect_preamble(input)?; + let chunk_size = preamble.chunk_data_size; + + // Grab all data associated with log (chunk) data + let (data, chunk_data) = take(chunk_size + chunk_preamble_size)(input)?; + ChunksetChunk::get_chunkset_data(chunk_data, preamble.chunk_tag, unified_log_data); + + let padding_size = padding_size(preamble.chunk_data_size); + if data.len() < padding_size as usize { + break; + } + let (data, _) = take(padding_size)(data)?; + if data.is_empty() { + break; + } + input = data; + if input.len() < chunk_preamble_size as usize { + warn!( + "[macos-unifiedlogs] Not enough data for Chunkset preamble header, needed 16 bytes. Got: {:?}", + input.len() + ); + break; + } + } + Ok((input, ())) + } + + // Parse the log entry (chunk) chunk based on type + fn get_chunkset_data( + data: &[u8], + chunk_type: u32, + unified_log_data: &mut UnifiedLogCatalogData, + ) { + let firehose_chunk = 0x6001; + let oversize_chunk = 0x6002; + let statedump_chunk = 0x6003; + let simpledump_chunk = 0x6004; + + if chunk_type == firehose_chunk { + let firehose_results = FirehosePreamble::parse_firehose_preamble(data); + match firehose_results { + Ok((_, firehose_data)) => unified_log_data.firehose.push(firehose_data), + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse firehose log entry (chunk): {:?}", + err + ), + } + } else if chunk_type == oversize_chunk { + let oversize_results = Oversize::parse_oversize(data); + match oversize_results { + Ok((_, oversize)) => unified_log_data.oversize.push(oversize), + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse oversize log entry (chunk): {:?}", + err + ), + } + } else if chunk_type == statedump_chunk { + let statedump_results = Statedump::parse_statedump(data); + match statedump_results { + Ok((_, statedump)) => unified_log_data.statedump.push(statedump), + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse statedump log entry (chunk): {:?}", + err + ), + } + } else if chunk_type == simpledump_chunk { + let simpledump_results = SimpleDump::parse_simpledump(data); + match simpledump_results { + Ok((_, simpledump)) => unified_log_data.simpledump.push(simpledump), + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse simpledump log entry (chunk): {:?}", + err + ), + } + } else { + error!( + "[macos-unifiedlogs] Unknown chunkset type: {:?}", + chunk_type + ); + } + } +} + +#[cfg(test)] +mod tests { + use super::ChunksetChunk; + use crate::catalog::CatalogChunk; + use crate::unified_log::UnifiedLogCatalogData; + use std::fs; + use std::path::PathBuf; + + #[test] + fn test_parse_chunkset() { + let test_chunk_chunkset = [ + 13, 96, 0, 0, 17, 0, 0, 0, 199, 84, 0, 0, 0, 0, 0, 0, 98, 118, 52, 49, 72, 248, 0, 0, + 183, 84, 0, 0, 49, 1, 96, 0, 1, 0, 32, 176, 2, 6, 0, 49, 0, 0, 87, 6, 0, 51, 0, 0, 225, + 8, 0, 115, 160, 2, 0, 16, 0, 0, 0, 30, 0, 179, 0, 0, 4, 0, 2, 2, 112, 58, 0, 0, 147, + 18, 0, 209, 102, 62, 252, 167, 0, 0, 8, 0, 4, 55, 0, 0, 3, 32, 0, 100, 4, 2, 230, 172, + 91, 79, 32, 0, 242, 3, 101, 46, 193, 170, 0, 0, 14, 0, 224, 61, 90, 79, 3, 0, 35, 1, + 65, 4, 89, 0, 102, 4, 0, 4, 2, 32, 141, 40, 0, 34, 96, 65, 40, 0, 46, 236, 154, 40, 0, + 38, 16, 185, 40, 0, 34, 204, 74, 40, 0, 46, 126, 160, 40, 0, 38, 64, 187, 40, 0, 64, + 58, 207, 225, 180, 120, 0, 151, 148, 177, 90, 79, 1, 0, 0, 1, 0, 120, 0, 38, 33, 184, + 40, 0, 49, 93, 63, 226, 40, 0, 46, 34, 152, 80, 0, 23, 96, 80, 0, 32, 167, 88, 40, 0, + 65, 20, 0, 145, 186, 40, 0, 18, 2, 200, 0, 2, 6, 0, 0, 209, 0, 0, 208, 0, 68, 160, 103, + 218, 18, 248, 0, 64, 160, 229, 106, 183, 24, 1, 80, 10, 178, 217, 18, 7, 32, 0, 86, 16, + 4, 2, 144, 183, 120, 0, 64, 179, 127, 107, 183, 160, 0, 48, 213, 86, 91, 80, 0, 9, 24, + 1, 23, 48, 160, 0, 146, 16, 121, 108, 183, 0, 0, 83, 0, 201, 160, 0, 18, 3, 40, 0, 2, + 6, 0, 240, 47, 64, 4, 0, 0, 57, 0, 69, 114, 114, 111, 114, 32, 68, 111, 109, 97, 105, + 110, 61, 88, 80, 67, 32, 99, 111, 110, 110, 101, 99, 116, 105, 111, 110, 32, 115, 101, + 116, 117, 112, 32, 102, 97, 105, 108, 101, 100, 32, 67, 111, 100, 101, 61, 45, 53, 51, + 54, 56, 55, 48, 50, 49, 50, 182, 0, 2, 176, 1, 38, 0, 166, 152, 0, 32, 173, 168, 112, + 0, 72, 23, 0, 68, 5, 232, 0, 32, 32, 4, 222, 1, 34, 78, 111, 48, 0, 38, 128, 163, 48, + 0, 32, 94, 171, 48, 0, 80, 14, 0, 39, 249, 89, 48, 0, 9, 200, 0, 38, 160, 164, 40, 0, + 32, 52, 185, 40, 0, 65, 28, 0, 6, 247, 40, 0, 3, 64, 1, 0, 88, 0, 147, 8, 0, 70, 97, + 105, 108, 117, 114, 101, 144, 0, 55, 2, 2, 123, 96, 2, 32, 225, 191, 56, 0, 64, 22, 0, + 13, 56, 130, 0, 44, 34, 1, 50, 0, 4, 192, 2, 17, 64, 62, 0, 51, 0, 0, 114, 8, 0, 19, + 245, 8, 0, 44, 48, 0, 192, 2, 2, 168, 1, 19, 170, 168, 1, 32, 225, 5, 136, 1, 2, 168, + 1, 0, 19, 0, 4, 80, 0, 34, 112, 15, 65, 0, 17, 105, 6, 0, 51, 0, 0, 240, 8, 0, 33, 96, + 15, 80, 0, 0, 235, 2, 1, 3, 0, 0, 16, 3, 80, 176, 84, 7, 0, 159, 61, 0, 241, 5, 0, 0, + 0, 202, 134, 6, 168, 0, 0, 22, 0, 246, 69, 4, 0, 1, 0, 34, 1, 34, 176, 0, 113, 55, 57, + 54, 46, 49, 48, 48, 8, 2, 115, 2, 2, 176, 217, 6, 0, 241, 48, 0, 241, 2, 196, 163, 242, + 168, 0, 0, 20, 0, 167, 134, 5, 0, 1, 0, 35, 2, 33, 218, 1, 35, 0, 4, 31, 0, 1, 112, 3, + 53, 64, 86, 7, 48, 0, 64, 237, 59, 38, 169, 82, 0, 32, 37, 77, 96, 0, 0, 144, 1, 115, + 3, 2, 128, 34, 7, 0, 4, 146, 0, 146, 143, 149, 159, 169, 0, 0, 59, 0, 208, 64, 0, 240, + 31, 128, 1, 103, 2, 0, 2, 0, 34, 2, 66, 4, 0, 0, 31, 0, 0, 4, 208, 7, 0, 0, 79, 68, 78, + 111, 100, 101, 67, 114, 101, 97, 116, 101, 87, 105, 116, 104, 78, 97, 109, 101, 65, + 110, 100, 79, 112, 52, 2, 18, 115, 57, 0, 4, 168, 0, 19, 255, 137, 0, 79, 142, 120, + 199, 172, 168, 0, 13, 53, 240, 63, 7, 48, 0, 32, 114, 157, 48, 0, 80, 63, 0, 49, 221, + 3, 128, 0, 16, 4, 184, 1, 254, 35, 1, 0, 32, 4, 1, 0, 1, 0, 66, 4, 2, 0, 18, 0, 32, 4, + 20, 0, 11, 0, 0, 0, 47, 65, 99, 116, 105, 118, 101, 32, 68, 105, 114, 101, 99, 116, + 111, 114, 121, 0, 32, 97, 115, 32, 104, 105, 100, 100, 101, 110, 136, 0, 63, 108, 90, + 252, 136, 0, 26, 32, 38, 109, 48, 0, 31, 52, 136, 0, 6, 82, 7, 0, 32, 4, 9, 136, 0, 89, + 76, 111, 99, 97, 108, 125, 0, 7, 176, 1, 4, 216, 0, 79, 96, 136, 23, 173, 8, 1, 13, 38, + 0, 70, 8, 1, 32, 58, 219, 48, 0, 80, 92, 0, 0, 156, 3, 16, 2, 1, 136, 1, 245, 26, 8, 0, + 66, 4, 8, 0, 64, 0, 47, 83, 101, 97, 114, 99, 104, 0, 47, 76, 105, 98, 114, 97, 114, + 121, 47, 80, 114, 101, 102, 101, 114, 101, 110, 99, 101, 115, 47, 79, 112, 101, 110, + 19, 1, 161, 47, 67, 111, 110, 102, 105, 103, 117, 114, 97, 163, 1, 19, 47, 58, 0, 97, + 46, 112, 108, 105, 115, 116, 177, 1, 0, 40, 2, 8, 128, 1, 32, 215, 239, 120, 0, 31, 43, + 248, 0, 6, 81, 8, 0, 32, 4, 10, 66, 2, 3, 76, 0, 0, 69, 0, 15, 240, 0, 0, 63, 9, 210, + 34, 240, 0, 14, 8, 120, 0, 32, 98, 229, 48, 0, 31, 53, 120, 0, 12, 1, 248, 1, 107, 76, + 68, 65, 80, 118, 51, 113, 1, 12, 240, 1, 63, 125, 141, 55, 128, 0, 26, 32, 64, 166, 48, + 0, 31, 56, 128, 0, 6, 82, 11, 0, 32, 4, 13, 240, 1, 4, 84, 1, 24, 101, 131, 0, 12, 128, + 0, 63, 53, 86, 72, 128, 0, 14, 8, 240, 1, 32, 242, 193, 48, 0, 25, 96, 240, 1, 128, 10, + 0, 66, 4, 10, 0, 66, 0, 198, 1, 95, 116, 97, 99, 116, 115, 242, 1, 33, 4, 60, 0, 3, + 244, 1, 12, 240, 1, 32, 116, 205, 120, 0, 31, 45, 248, 0, 6, 82, 10, 0, 32, 4, 12, 240, + 1, 4, 74, 0, 1, 241, 1, 0, 72, 0, 38, 192, 85, 176, 2, 176, 136, 135, 246, 173, 0, 0, + 21, 0, 144, 80, 4, 176, 2, 16, 1, 176, 2, 20, 7, 28, 3, 15, 32, 2, 0, 79, 24, 29, 149, + 175, 16, 3, 13, 38, 112, 83, 96, 0, 64, 125, 8, 150, 175, 32, 5, 48, 138, 66, 4, 24, 4, + 1, 96, 0, 144, 8, 0, 65, 112, 112, 108, 101, 73, 68, 96, 0, 3, 216, 0, 4, 208, 4, 79, + 222, 128, 168, 175, 80, 2, 3, 113, 4, 0, 66, 4, 5, 0, 15, 72, 4, 99, 1, 0, 0, 115, 117, + 98, 167, 0, 118, 47, 68, 101, 102, 97, 117, 108, 24, 3, 38, 176, 31, 128, 0, 64, 162, + 25, 190, 176, 64, 5, 32, 114, 81, 24, 5, 134, 0, 0, 2, 1, 2, 0, 208, 70, 64, 5, 160, + 90, 14, 203, 176, 0, 0, 12, 0, 96, 1, 30, 1, 52, 0, 128, 36, 145, 5, 86, 0, 3, 2, 0, + 71, 40, 0, 32, 253, 30, 40, 0, 21, 37, 40, 0, 38, 139, 33, 208, 0, 31, 15, 137, 0, 0, + 0, 88, 2, 83, 192, 20, 7, 0, 1, 216, 0, 32, 85, 104, 64, 0, 81, 8, 0, 250, 163, 5, 136, + 0, 147, 4, 0, 3, 2, 192, 79, 7, 0, 3, 32, 0, 57, 148, 188, 204, 96, 0, 47, 199, 50, 96, + 0, 12, 71, 0, 3, 2, 48, 160, 0, 57, 147, 153, 217, 64, 0, 47, 100, 35, 64, 0, 13, 70, + 2, 2, 0, 86, 40, 1, 166, 212, 224, 225, 176, 0, 0, 29, 0, 48, 81, 8, 2, 15, 216, 0, 2, + 11, 64, 2, 64, 32, 44, 226, 176, 224, 1, 8, 64, 2, 21, 8, 234, 4, 14, 64, 2, 79, 16, + 238, 115, 177, 64, 2, 9, 4, 160, 1, 4, 56, 1, 64, 130, 181, 118, 177, 160, 1, 31, 97, + 160, 1, 4, 4, 40, 0, 32, 223, 191, 40, 0, 21, 30, 40, 0, 8, 160, 1, 9, 144, 0, 3, 120, + 1, 19, 47, 56, 0, 57, 54, 91, 135, 56, 0, 8, 120, 1, 12, 56, 0, 0, 112, 1, 4, 112, 0, + 57, 190, 193, 139, 56, 0, 8, 112, 1, 10, 56, 0, 10, 104, 1, 64, 177, 67, 161, 177, 48, + 1, 8, 104, 1, 12, 48, 0, 8, 160, 3, 32, 19, 231, 48, 0, 25, 29, 160, 3, 15, 152, 1, 5, + 8, 208, 1, 34, 183, 240, 56, 0, 8, 104, 0, 15, 56, 0, 5, 23, 240, 112, 8, 32, 204, 251, + 56, 0, 64, 8, 0, 143, 82, 8, 2, 0, 112, 8, 115, 10, 2, 240, 103, 3, 0, 70, 248, 0, 240, + 13, 17, 84, 126, 178, 0, 0, 24, 0, 171, 242, 1, 0, 194, 117, 213, 238, 186, 212, 58, + 134, 183, 79, 22, 243, 230, 43, 245, 125, 123, 1, 102, 4, 0, 10, 2, 48, 104, 48, 0, 32, + 10, 93, 48, 0, 79, 48, 0, 133, 243, 48, 0, 2, 64, 4, 0, 4, 100, 120, 3, 33, 4, 250, 6, + 0, 2, 12, 0, 32, 244, 1, 168, 3, 70, 10, 0, 16, 105, 72, 0, 144, 221, 107, 130, 178, 0, + 0, 28, 0, 98, 101, 0, 94, 0, 0, 128, 68, 245, 80, 0, 1, 61, 0, 131, 16, 5, 2, 80, 168, + 7, 6, 46, 176, 0, 117, 251, 35, 18, 185, 0, 0, 148, 184, 3, 83, 58, 83, 239, 5, 9, 168, + 9, 250, 37, 126, 0, 116, 97, 98, 108, 101, 32, 39, 114, 101, 99, 58, 112, 101, 111, + 112, 108, 101, 39, 32, 97, 108, 114, 101, 97, 100, 121, 32, 101, 120, 105, 115, 116, + 115, 32, 105, 110, 32, 34, 67, 82, 69, 65, 84, 69, 32, 84, 65, 66, 76, 69, 45, 0, 241, + 6, 40, 39, 102, 105, 108, 101, 116, 105, 109, 101, 39, 32, 73, 78, 84, 69, 71, 69, 82, + 44, 32, 20, 0, 32, 110, 97, 20, 0, 240, 1, 84, 69, 88, 84, 32, 85, 78, 73, 81, 85, 69, + 32, 67, 79, 76, 76, 71, 0, 145, 78, 79, 67, 65, 83, 69, 41, 59, 34, 161, 0, 12, 176, 0, + 127, 64, 85, 19, 185, 0, 0, 154, 176, 0, 2, 25, 132, 176, 0, 143, 114, 111, 116, 111, + 99, 111, 108, 115, 179, 0, 21, 6, 48, 0, 15, 182, 0, 47, 0, 216, 3, 10, 104, 1, 47, 33, + 175, 184, 0, 20, 143, 99, 111, 109, 112, 117, 116, 101, 114, 184, 0, 21, 7, 48, 0, 15, + 184, 0, 65, 117, 116, 252, 22, 185, 0, 0, 146, 0, 6, 8, 32, 2, 24, 124, 112, 1, 47, + 117, 115, 180, 0, 23, 3, 44, 0, 15, 176, 0, 65, 127, 191, 140, 202, 185, 0, 0, 152, + 176, 0, 2, 24, 130, 176, 0, 127, 110, 101, 116, 119, 111, 114, 107, 103, 1, 21, 6, 47, + 0, 15, 182, 0, 43, 12, 208, 2, 127, 197, 204, 204, 185, 0, 0, 164, 176, 0, 2, 24, 142, + 176, 0, 4, 232, 1, 95, 103, 114, 111, 117, 112, 182, 0, 21, 12, 53, 0, 15, 188, 0, 43, + 0, 145, 3, 12, 192, 0, 63, 139, 62, 205, 216, 2, 19, 143, 101, 116, 104, 101, 114, 110, + 101, 116, 187, 0, 21, 7, 48, 0, 15, 182, 0, 47, 14, 144, 3, 32, 7, 133, 184, 0, 31, + 160, 120, 1, 2, 24, 138, 120, 1, 207, 97, 117, 116, 111, 109, 111, 117, 110, 116, 109, + 97, 112, 187, 0, 20, 10, 51, 0, 15, 190, 0, 43, 4, 128, 15, 16, 8, 102, 15, 0, 129, 1, + 11, 3, 0, 30, 248, 128, 15, 69, 0, 43, 44, 144, 37, 0, 177, 72, 185, 10, 0, 0, 0, 6, 0, + 107, 182, 24, 19, 0, 0, 246, 8, 23, 63, 32, 0, 34, 153, 226, 32, 0, 23, 130, 32, 0, 24, + 113, 32, 0, 18, 230, 32, 0, 23, 153, 32, 0, 49, 128, 100, 157, 76, 0, 0, 5, 0, 209, + 204, 59, 12, 0, 0, 0, 109, 0, 113, 171, 10, 0, 2, 54, 6, 160, 97, 0, 68, 97, 114, 119, + 105, 110, 32, 75, 240, 1, 96, 108, 32, 86, 101, 114, 115, 124, 17, 240, 59, 50, 48, 46, + 54, 46, 48, 58, 32, 84, 117, 101, 32, 79, 99, 116, 32, 49, 50, 32, 49, 56, 58, 51, 51, + 58, 52, 50, 32, 80, 68, 84, 32, 50, 48, 50, 49, 59, 32, 114, 111, 111, 116, 58, 120, + 110, 117, 45, 55, 49, 57, 53, 46, 49, 52, 49, 46, 56, 126, 49, 47, 82, 69, 76, 69, 65, + 83, 69, 95, 88, 56, 54, 95, 54, 52, 120, 0, 0, 200, 0, 48, 22, 204, 143, 11, 0, 1, 4, + 0, 64, 193, 17, 159, 0, 8, 9, 176, 217, 37, 21, 0, 0, 1, 2, 4, 0, 0, 32, 23, 0, 1, 40, + 0, 38, 34, 205, 40, 0, 64, 227, 197, 250, 5, 3, 17, 33, 145, 39, 40, 0, 50, 8, 32, 95, + 217, 4, 0, 40, 0, 23, 83, 40, 0, 32, 235, 205, 40, 0, 50, 12, 0, 165, 40, 0, 51, 4, 80, + 160, 137, 16, 86, 0, 2, 0, 106, 203, 80, 0, 32, 88, 236, 40, 0, 242, 5, 24, 0, 208, 16, + 137, 0, 0, 3, 2, 4, 211, 164, 26, 0, 2, 4, 45, 27, 5, 0, 52, 0, 0, 88, 0, 38, 95, 19, + 48, 0, 64, 13, 164, 183, 9, 168, 0, 48, 33, 255, 136, 128, 0, 18, 4, 86, 0, 0, 72, 8, + 70, 2, 0, 216, 7, 184, 1, 241, 0, 18, 58, 184, 9, 0, 0, 30, 0, 156, 0, 137, 0, 1, 4, 1, + 39, 0, 14, 6, 0, 2, 56, 0, 53, 8, 168, 142, 56, 0, 64, 8, 87, 185, 9, 240, 1, 49, 34, + 228, 136, 20, 0, 0, 128, 0, 49, 102, 174, 154, 12, 0, 0, 5, 0, 240, 1, 21, 47, 194, 9, + 0, 0, 18, 0, 72, 31, 137, 0, 0, 2, 2, 4, 87, 2, 48, 2, 4, 8, 27, 0, 1, 4, 0, 0, 48, 0, + 38, 207, 14, 80, 0, 32, 236, 193, 48, 0, 81, 12, 0, 64, 222, 9, 176, 0, 34, 16, 39, 27, + 0, 0, 40, 0, 23, 246, 40, 0, 34, 204, 197, 40, 0, 19, 120, 40, 0, 33, 196, 9, 39, 0, 1, + 160, 0, 38, 45, 121, 80, 0, 224, 85, 240, 195, 9, 0, 0, 33, 0, 227, 25, 13, 0, 2, 3, + 14, 18, 32, 9, 0, 174, 1, 17, 4, 6, 0, 146, 128, 0, 119, 113, 108, 95, 105, 110, 105, + 173, 12, 3, 232, 1, 23, 131, 64, 0, 32, 221, 78, 90, 0, 79, 33, 0, 104, 26, 64, 0, 5, + 29, 112, 64, 0, 53, 30, 200, 141, 128, 0, 49, 251, 82, 197, 0, 1, 49, 238, 226, 136, 0, + 1, 17, 53, 0, 1, 18, 116, 5, 2, 3, 112, 0, 38, 30, 187, 136, 1, 64, 208, 221, 98, 12, + 48, 2, 51, 204, 66, 27, 224, 2, 81, 4, 0, 97, 110, 100, 216, 0, 38, 197, 178, 40, 0, + 32, 160, 239, 40, 0, 81, 12, 0, 160, 224, 26, 40, 1, 19, 6, 26, 0, 0, 0, 1, 83, 194, + 113, 141, 0, 101, 16, 0, 49, 7, 238, 111, 80, 0, 48, 45, 0, 5, 40, 0, 50, 8, 0, 112, + 25, 0, 0, 40, 0, 82, 16, 240, 159, 0, 113, 15, 0, 80, 0, 170, 126, 7, 35, 40, 2, 98, + 59, 201, 132, 0, 1, 1, 250, 1, 0, 27, 0, 1, 40, 0, 22, 218, 40, 0, 179, 162, 185, 8, + 35, 0, 0, 63, 0, 240, 93, 132, 16, 1, 81, 30, 0, 34, 4, 30, 86, 1, 0, 92, 18, 211, 99, + 104, 97, 110, 103, 101, 80, 111, 119, 101, 114, 83, 116, 224, 18, 240, 3, 84, 97, 103, + 84, 111, 80, 114, 105, 118, 0, 79, 78, 95, 83, 84, 65, 84, 69, 248, 0, 85, 8, 0, 112, + 14, 6, 128, 0, 64, 199, 86, 12, 35, 248, 14, 98, 230, 145, 52, 1, 128, 255, 218, 3, + 113, 7, 0, 65, 67, 80, 73, 58, 89, 3, 12, 48, 0, 34, 226, 110, 48, 0, 47, 4, 146, 48, + 0, 19, 32, 198, 132, 48, 0, 25, 58, 96, 0, 163, 44, 0, 82, 83, 68, 80, 32, 48, 120, 48, + 1, 0, 144, 66, 70, 70, 56, 55, 48, 48, 48, 32, 15, 0, 240, 0, 50, 52, 32, 40, 118, 48, + 50, 32, 86, 77, 87, 65, 82, 69, 41, 13, 1, 1, 16, 1, 10, 136, 0, 34, 29, 135, 88, 0, 8, + 136, 0, 15, 88, 0, 49, 32, 166, 138, 88, 0, 25, 16, 176, 0, 61, 2, 0, 10, 8, 1, 34, 44, + 141, 40, 0, 8, 128, 0, 15, 40, 0, 1, 49, 209, 119, 13, 48, 1, 8, 0, 1, 15, 96, 1, 9, + 34, 33, 122, 48, 0, 8, 88, 0, 15, 48, 0, 9, 32, 24, 132, 48, 0, 25, 90, 176, 0, 109, + 76, 0, 88, 83, 68, 84, 96, 1, 33, 54, 52, 96, 1, 32, 53, 67, 96, 1, 17, 49, 168, 11, + 240, 1, 76, 32, 32, 52, 52, 48, 66, 88, 32, 32, 32, 32, 48, 54, 48, 52, 32, 0, 0, 121, + 1, 175, 32, 32, 48, 49, 51, 50, 52, 50, 55, 50, 128, 1, 5, 34, 238, 134, 120, 0, 8, + 168, 0, 15, 120, 0, 81, 32, 249, 138, 120, 0, 15, 160, 1, 15, 34, 199, 140, 40, 0, 8, + 160, 0, 15, 160, 1, 1, 32, 140, 220, 40, 0, 25, 21, 80, 0, 15, 112, 1, 9, 34, 255, 221, + 48, 0, 8, 88, 0, 15, 48, 0, 9, 32, 98, 229, 48, 0, 12, 160, 1, 62, 83, 82, 65, 160, 1, + 17, 67, 0, 3, 48, 49, 50, 56, 160, 1, 16, 51, 135, 1, 113, 65, 82, 69, 32, 69, 70, 73, + 46, 0, 4, 160, 1, 16, 49, 25, 0, 17, 32, 202, 1, 63, 48, 55, 67, 32, 3, 6, 34, 3, 232, + 120, 0, 8, 168, 0, 33, 76, 0, 74, 0, 12, 24, 2, 15, 120, 0, 58, 32, 215, 235, 120, 0, + 15, 160, 1, 15, 34, 149, 237, 40, 0, 8, 160, 0, 15, 160, 1, 1, 49, 245, 29, 14, 112, 1, + 15, 64, 3, 21, 34, 83, 31, 48, 0, 8, 88, 0, 15, 160, 1, 9, 32, 70, 38, 48, 0, 12, 160, + 1, 60, 70, 65, 67, 160, 4, 65, 68, 50, 66, 67, 118, 1, 32, 70, 52, 160, 1, 31, 52, 64, + 3, 7, 49, 80, 84, 76, 160, 1, 95, 70, 52, 50, 52, 48, 64, 3, 5, 34, 236, 40, 120, 0, 8, + 168, 0, 15, 120, 0, 81, 32, 196, 44, 120, 0, 15, 160, 1, 15, 34, 128, 46, 40, 0, 8, + 160, 0, 15, 160, 1, 1, 32, 208, 154, 40, 0, 15, 64, 3, 23, 34, 94, 156, 48, 0, 8, 88, + 0, 15, 160, 1, 9, 32, 131, 163, 48, 0, 12, 160, 1, 31, 68, 224, 4, 0, 145, 49, 69, 56, + 32, 48, 48, 54, 48, 68, 160, 1, 240, 0, 49, 32, 80, 84, 76, 84, 68, 32, 32, 67, 117, + 115, 116, 111, 109, 224, 4, 0, 189, 1, 0, 224, 4, 223, 73, 78, 84, 76, 32, 50, 48, 49, + 51, 48, 56, 50, 51, 160, 1, 5, 34, 53, 166, 120, 0, 8, 168, 0, 15, 120, 0, 81, 32, 5, + 170, 120, 0, 15, 160, 1, 15, 34, 191, 171, 40, 0, 8, 160, 0, 15, 160, 1, 1, 32, 56, + 221, 40, 0, 15, 160, 1, 23, 34, 153, 222, 48, 0, 8, 88, 0, 15, 160, 1, 9, 32, 153, 226, + 48, 0, 25, 45, 96, 0, 16, 31, 200, 2, 27, 83, 128, 6, 16, 69, 123, 1, 0, 130, 1, 32, + 52, 48, 83, 6, 12, 80, 7, 34, 87, 228, 72, 0, 8, 120, 0, 15, 72, 0, 33, 32, 169, 230, + 72, 0, 15, 64, 1, 15, 34, 97, 232, 40, 0, 8, 112, 0, 15, 64, 1, 1, 49, 188, 99, 15, 16, + 1, 15, 128, 4, 21, 34, 239, 101, 48, 0, 8, 88, 0, 15, 64, 1, 9, 32, 218, 107, 48, 0, + 15, 64, 1, 47, 34, 143, 109, 72, 0, 8, 120, 0, 15, 64, 1, 33, 32, 234, 111, 72, 0, 15, + 64, 1, 15, 34, 245, 113, 40, 0, 8, 112, 0, 15, 64, 1, 1, 32, 28, 188, 40, 0, 15, 128, + 2, 23, 34, 127, 189, 48, 0, 8, 88, 0, 15, 64, 1, 9, 32, 27, 196, 48, 0, 12, 32, 4, 75, + 65, 80, 73, 67, 128, 2, 50, 68, 52, 50, 0, 9, 32, 66, 50, 192, 5, 8, 96, 7, 1, 46, 0, + 15, 96, 7, 28, 34, 212, 198, 120, 0, 8, 168, 0, 33, 76, 0, 74, 0, 15, 120, 0, 58, 4, + 24, 16, 16, 0, 193, 13, 0, 57, 3, 11, 3, 0, 29, 240, 24, 16, 10, 40, 11, 32, 247, 203, + 168, 0, 15, 208, 1, 15, 34, 125, 208, 40, 0, 8, 208, 0, 15, 208, 1, 1, 32, 203, 254, + 40, 0, 15, 208, 1, 23, 49, 37, 0, 16, 48, 0, 8, 88, 0, 15, 208, 1, 9, 32, 69, 6, 48, 0, + 12, 208, 1, 77, 77, 67, 70, 71, 208, 1, 33, 68, 54, 144, 7, 19, 51, 208, 10, 2, 48, 12, + 0, 48, 9, 1, 46, 0, 15, 208, 1, 28, 34, 234, 8, 120, 0, 8, 168, 0, 33, 76, 0, 74, 0, + 15, 120, 0, 74, 32, 186, 12, 120, 0, 15, 160, 1, 15, 34, 117, 14, 40, 0, 8, 160, 0, 15, + 160, 1, 1, 32, 92, 60, 40, 0, 15, 160, 1, 23, 34, 190, 61, 48, 0, 8, 88, 0, 15, 160, 1, + 9, 32, 84, 67, 48, 0, 12, 160, 1, 60, 72, 80, 69, 208, 10, 66, 68, 53, 49, 50, 160, 1, + 1, 208, 10, 1, 183, 10, 0, 208, 10, 0, 94, 12, 2, 47, 0, 0, 29, 0, 0, 21, 6, 0, 18, 0, + 1, 42, 0, 0, 4, 0, 15, 144, 7, 5, 34, 13, 70, 120, 0, 8, 168, 0, 34, 76, 0, 73, 0, 10, + 160, 1, 15, 120, 0, 59, 32, 207, 73, 120, 0, 15, 160, 1, 15, 34, 135, 75, 40, 0, 8, + 160, 0, 15, 160, 1, 1, 32, 243, 203, 40, 0, 15, 160, 1, 23, 34, 96, 206, 48, 0, 8, 88, + 0, 15, 160, 1, 9, 32, 127, 214, 48, 0, 12, 160, 1, 47, 87, 65, 160, 1, 0, 33, 52, 65, + 118, 1, 2, 112, 12, 9, 160, 1, 2, 47, 0, 2, 16, 14, 1, 25, 0, 1, 208, 10, 0, 45, 0, 31, + 49, 160, 1, 5, 34, 72, 217, 120, 0, 8, 168, 0, 34, 76, 0, 73, 0, 11, 160, 1, 15, 120, + 0, 58, 32, 54, 221, 120, 0, 15, 160, 1, 15, 34, 84, 223, 40, 0, 8, 160, 0, 15, 160, 1, + 1, 49, 121, 42, 17, 112, 1, 15, 240, 7, 21, 34, 227, 43, 48, 0, 8, 88, 0, 15, 160, 1, + 9, 32, 16, 50, 48, 0, 13, 160, 1, 46, 83, 77, 160, 1, 18, 55, 64, 3, 15, 160, 1, 1, 1, + 47, 0, 15, 160, 1, 26, 34, 97, 68, 120, 0, 8, 168, 0, 34, 76, 0, 73, 0, 11, 160, 1, 15, + 120, 0, 58, 32, 248, 73, 120, 0, 15, 160, 1, 15, 34, 144, 76, 40, 0, 8, 160, 0, 15, + 160, 1, 1, 49, 201, 225, 82, 112, 1, 15, 160, 1, 21, 34, 201, 227, 48, 0, 8, 88, 0, 15, + 160, 1, 9, 32, 109, 232, 48, 0, 25, 65, 176, 0, 64, 51, 0, 49, 32, 18, 19, 81, 32, 65, + 77, 76, 32, 43, 29, 241, 18, 115, 32, 115, 117, 99, 99, 101, 115, 115, 102, 117, 108, + 108, 121, 32, 97, 99, 113, 117, 105, 114, 101, 100, 32, 97, 110, 100, 32, 108, 111, 97, + 100, 101, 193, 29, 0, 203, 4, 12, 232, 10, 34, 77, 234, 96, 0, 8, 144, 0, 15, 96, 0, + 57, 32, 29, 237, 96, 0, 15, 112, 1, 15, 34, 188, 238, 40, 0, 8, 136, 0, 2, 112, 1, 100, + 2, 0, 158, 121, 158, 0, 153, 21, 179, 43, 245, 119, 35, 0, 0, 17, 0, 220, 127, 134, 24, + 21, 99, 5, 0, 65, 77, 70, 73, 31, 0, 1, 32, 21, 23, 225, 48, 0, 224, 63, 8, 120, 35, 0, + 0, 51, 0, 142, 128, 134, 0, 2, 2, 248, 21, 114, 28, 0, 34, 4, 28, 0, 5, 236, 34, 144, + 32, 77, 111, 98, 105, 108, 101, 32, 70, 5, 0, 151, 73, 110, 116, 101, 103, 114, 105, + 116, 121, 82, 0, 12, 128, 0, 32, 225, 37, 80, 0, 23, 20, 128, 0, 145, 8, 0, 83, 97, + 110, 100, 98, 111, 120, 130, 0, 0, 48, 0, 8, 128, 0, 119, 152, 19, 122, 35, 0, 0, 50, + 128, 0, 242, 3, 24, 0, 34, 4, 24, 0, 8, 0, 83, 101, 97, 116, 98, 101, 108, 116, 32, + 115, 63, 0, 121, 32, 112, 111, 108, 105, 99, 121, 78, 0, 0, 104, 20, 10, 128, 0, 119, + 253, 72, 123, 35, 0, 0, 23, 128, 0, 194, 11, 0, 81, 117, 97, 114, 97, 110, 116, 105, + 110, 101, 48, 0, 8, 128, 0, 32, 243, 81, 48, 0, 23, 47, 128, 0, 89, 18, 0, 34, 4, 18, + 54, 0, 4, 122, 0, 10, 72, 0, 85, 8, 0, 192, 219, 4, 120, 1, 241, 0, 60, 201, 141, 35, + 0, 0, 54, 0, 178, 117, 109, 1, 128, 255, 3, 66, 23, 210, 23, 0, 34, 4, 23, 0, 5, 0, 1, + 4, 28, 0, 0, 80, 1, 243, 3, 67, 114, 101, 100, 101, 110, 116, 105, 97, 108, 77, 97, + 110, 97, 103, 101, 114, 0, 85, 23, 0, 120, 2, 38, 190, 173, 80, 0, 160, 124, 123, 142, + 35, 0, 0, 251, 0, 20, 41, 80, 0, 32, 2, 5, 154, 1, 53, 6, 0, 2, 17, 24, 245, 65, 34, 4, + 6, 0, 4, 0, 34, 4, 10, 0, 199, 0, 2, 4, 182, 0, 0, 0, 118, 97, 108, 117, 101, 0, 45, + 45, 45, 0, 47, 83, 121, 115, 116, 101, 109, 47, 86, 111, 108, 117, 109, 101, 115, 47, + 68, 97, 116, 97, 47, 83, 87, 69, 47, 109, 97, 99, 79, 83, 47, 66, 117, 105, 108, 100, + 82, 111, 111, 116, 115, 47, 50, 50, 48, 101, 56, 97, 49, 98, 55, 57, 220, 39, 241, 14, + 67, 97, 99, 104, 101, 115, 47, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 120, 98, + 115, 47, 83, 111, 117, 114, 99, 101, 115, 47, 0, 37, 13, 196, 0, 15, 23, 0, 4, 175, 45, + 52, 49, 55, 46, 49, 52, 48, 46, 50, 33, 0, 4, 97, 47, 83, 101, 114, 118, 105, 88, 0, + 34, 67, 77, 150, 26, 3, 18, 0, 53, 46, 99, 112, 128, 23, 70, 8, 0, 17, 220, 24, 1, 32, + 190, 166, 24, 1, 65, 90, 0, 107, 119, 24, 1, 16, 7, 24, 1, 4, 104, 1, 0, 176, 24, 17, + 0, 190, 2, 80, 3, 0, 34, 4, 31, 136, 43, 33, 4, 34, 6, 0, 63, 37, 0, 3, 128, 1, 10, 38, + 78, 79, 3, 0, 1, 167, 2, 1, 64, 22, 38, 221, 154, 120, 0, 32, 99, 202, 120, 0, 80, 56, + 0, 39, 84, 108, 120, 0, 1, 224, 1, 96, 4, 0, 34, 4, 4, 0, 88, 26, 16, 6, 224, 1, 241, + 2, 67, 77, 0, 69, 110, 118, 95, 83, 101, 116, 86, 97, 114, 105, 97, 98, 108, 181, 42, + 97, 80, 97, 114, 97, 109, 115, 80, 0, 38, 13, 155, 80, 0, 34, 67, 208, 80, 0, 31, 80, + 80, 0, 2, 0, 247, 24, 15, 80, 0, 15, 38, 222, 49, 80, 0, 32, 183, 211, 80, 0, 49, 14, + 0, 110, 80, 0, 2, 106, 27, 0, 201, 0, 0, 120, 0, 23, 228, 40, 0, 32, 64, 213, 40, 0, + 50, 8, 0, 132, 40, 0, 1, 152, 0, 38, 47, 54, 72, 0, 32, 32, 241, 32, 0, 91, 51, 0, 153, + 11, 107, 232, 0, 64, 21, 0, 2, 4, 116, 28, 0, 152, 0, 70, 73, 110, 105, 116, 7, 2, 49, + 69, 110, 103, 92, 3, 4, 112, 0, 8, 56, 1, 32, 139, 247, 80, 0, 15, 56, 1, 5, 19, 5, 80, + 0, 15, 56, 1, 23, 34, 133, 252, 80, 0, 15, 56, 1, 53, 32, 228, 255, 80, 0, 15, 56, 1, + 15, 61, 70, 1, 143, 56, 1, 8, 232, 0, 32, 230, 38, 32, 0, 15, 232, 0, 5, 31, 23, 232, + 0, 30, 34, 45, 45, 80, 0, 15, 232, 0, 53, 32, 144, 48, 80, 0, 8, 232, 0, 0, 100, 2, 0, + 16, 5, 10, 32, 2, 32, 226, 49, 40, 0, 10, 32, 2, 8, 232, 0, 32, 250, 53, 32, 0, 15, + 232, 0, 5, 0, 204, 30, 0, 32, 2, 15, 208, 1, 23, 34, 186, 58, 80, 0, 15, 232, 0, 3, 31, + 22, 80, 0, 18, 8, 8, 3, 32, 193, 61, 80, 0, 8, 232, 0, 21, 79, 232, 0, 8, 40, 0, 44, + 99, 63, 40, 0, 31, 99, 40, 0, 2, 44, 202, 64, 40, 0, 2, 106, 7, 0, 56, 3, 8, 80, 0, 44, + 37, 66, 40, 0, 1, 143, 27, 5, 16, 16, 33, 240, 14, 15, 0, 13, 4, 0, 33, 224, 14, 42, + 16, 20, 3, 24, 0, 12, 88, 0, 44, 10, 68, 88, 0, 17, 49, 43, 0, 12, 40, 0, 44, 174, 72, + 40, 0, 2, 57, 49, 12, 40, 0, 44, 26, 74, 40, 0, 2, 168, 0, 12, 40, 0, 44, 120, 75, 40, + 0, 15, 80, 0, 3, 44, 213, 76, 40, 0, 1, 47, 20, 1, 88, 2, 8, 32, 1, 44, 49, 78, 40, 0, + 15, 80, 0, 3, 44, 140, 79, 40, 0, 15, 240, 0, 3, 44, 231, 80, 40, 0, 31, 44, 40, 0, 2, + 44, 68, 82, 40, 0, 15, 240, 0, 3, 44, 157, 83, 40, 0, 15, 120, 0, 3, 44, 250, 84, 40, + 0, 31, 56, 40, 0, 2, 44, 87, 86, 40, 0, 31, 58, 40, 0, 2, 44, 182, 87, 40, 0, 15, 24, + 1, 3, 44, 16, 89, 40, 0, 15, 160, 0, 3, 44, 113, 90, 40, 0, 15, 120, 0, 3, 44, 206, 91, + 40, 0, 15, 184, 1, 3, 44, 43, 93, 40, 0, 0, 154, 31, 2, 56, 4, 8, 224, 1, 44, 148, 94, + 40, 0, 1, 39, 0, 1, 40, 0, 8, 96, 4, 32, 203, 95, 40, 0, 10, 96, 4, 38, 186, 156, 128, + 6, 32, 217, 100, 32, 0, 65, 60, 0, 151, 99, 104, 7, 22, 4, 104, 7, 17, 20, 24, 10, 90, + 4, 0, 2, 4, 25, 22, 4, 0, 223, 8, 182, 80, 114, 111, 118, 105, 100, 101, 114, 0, 115, + 101, 160, 3, 8, 88, 0, 47, 164, 106, 88, 0, 15, 31, 27, 88, 0, 32, 47, 28, 112, 88, 0, + 15, 11, 198, 4, 15, 176, 0, 18, 47, 152, 117, 88, 0, 15, 31, 29, 88, 0, 20, 8, 192, 5, + 32, 171, 122, 88, 0, 15, 192, 5, 5, 0, 2, 54, 15, 192, 5, 27, 34, 73, 127, 80, 0, 15, + 192, 5, 3, 0, 100, 6, 15, 80, 0, 15, 8, 72, 2, 32, 31, 130, 80, 0, 8, 192, 5, 1, 71, 2, + 13, 72, 2, 32, 96, 131, 40, 0, 10, 72, 2, 8, 232, 0, 32, 210, 134, 32, 0, 15, 232, 0, + 5, 31, 26, 152, 0, 18, 8, 176, 9, 34, 98, 139, 80, 0, 15, 232, 0, 53, 32, 48, 142, 80, + 0, 15, 232, 0, 15, 32, 92, 143, 40, 0, 10, 232, 0, 38, 252, 174, 48, 3, 32, 34, 160, + 32, 0, 65, 56, 0, 192, 106, 48, 3, 1, 194, 13, 17, 31, 254, 10, 249, 4, 5, 0, 65, 67, + 77, 70, 105, 114, 115, 116, 82, 101, 115, 112, 111, 110, 100, 101, 114, 100, 11, 2, + 122, 12, 0, 88, 1, 38, 22, 161, 80, 0, 32, 51, 203, 80, 0, 70, 33, 0, 62, 114, 80, 0, + 80, 8, 0, 34, 4, 8, 18, 14, 98, 67, 77, 82, 77, 45, 83, 57, 0, 1, 150, 1, 2, 8, 4, 23, + 127, 184, 12, 34, 5, 214, 64, 0, 47, 50, 151, 64, 0, 5, 29, 67, 64, 0, 38, 76, 200, + 128, 0, 32, 207, 233, 64, 0, 65, 98, 0, 13, 39, 224, 11, 1, 0, 4, 226, 17, 0, 34, 4, + 17, 0, 34, 0, 34, 4, 51, 0, 15, 0, 28, 37, 12, 50, 12, 1, 85, 0, 16, 86, 3, 13, 240, + 15, 70, 114, 111, 109, 66, 111, 111, 116, 65, 114, 103, 65, 108, 105, 97, 115, 101, + 115, 85, 73, 110, 116, 51, 50, 0, 97, 99, 99, 45, 99, 222, 12, 68, 32, 115, 105, 122, + 248, 35, 0, 0, 1, 8, 128, 0, 32, 70, 243, 128, 0, 31, 104, 128, 0, 6, 0, 6, 11, 48, 0, + 141, 39, 92, 1, 14, 78, 1, 15, 128, 0, 21, 66, 101, 120, 112, 105, 35, 53, 1, 64, 1, + 38, 240, 119, 0, 1, 64, 107, 7, 144, 35, 2, 55, 33, 128, 217, 128, 11, 1, 208, 1, 17, + 6, 238, 13, 1, 208, 1, 33, 82, 77, 233, 0, 2, 120, 1, 38, 245, 244, 56, 0, 32, 10, 25, + 56, 0, 65, 33, 0, 203, 231, 56, 1, 1, 56, 0, 10, 184, 1, 19, 65, 58, 0, 2, 249, 0, 0, + 120, 0, 8, 248, 0, 32, 249, 33, 64, 0, 31, 111, 248, 0, 6, 112, 28, 0, 2, 4, 128, 81, + 1, 132, 0, 15, 248, 0, 30, 211, 110, 97, 108, 121, 116, 105, 99, 115, 32, 99, 111, 108, + 108, 242, 57, 98, 112, 101, 114, 105, 111, 100, 200, 0, 8, 136, 0, 32, 209, 43, 136, 0, + 31, 103, 136, 0, 6, 16, 20, 136, 0, 47, 244, 3, 136, 0, 33, 2, 198, 15, 210, 32, 109, + 111, 100, 101, 32, 116, 105, 109, 101, 111, 117, 116, 128, 0, 38, 109, 249, 72, 1, 32, + 151, 63, 128, 0, 65, 77, 0, 14, 252, 72, 1, 1, 128, 2, 2, 72, 1, 19, 33, 122, 0, 80, + 34, 4, 41, 0, 4, 128, 0, 242, 9, 82, 77, 45, 65, 0, 110, 111, 116, 105, 102, 121, 83, + 116, 97, 110, 100, 97, 114, 100, 77, 111, 100, 101, 84, 91, 0, 17, 67, 225, 37, 80, + 100, 0, 89, 69, 83, 113, 1, 12, 112, 1, 32, 14, 73, 104, 0, 31, 114, 232, 0, 6, 16, 31, + 104, 2, 32, 163, 2, 104, 0, 15, 112, 1, 29, 243, 0, 40, 98, 111, 117, 110, 100, 101, + 100, 41, 32, 103, 114, 97, 99, 101, 107, 1, 6, 243, 0, 0, 143, 0, 1, 120, 1, 8, 248, 0, + 32, 131, 81, 144, 0, 61, 76, 0, 174, 248, 0, 19, 32, 138, 0, 61, 34, 4, 40, 248, 0, 16, + 71, 97, 0, 17, 80, 96, 0, 15, 247, 0, 3, 1, 104, 0, 8, 224, 1, 32, 41, 100, 104, 0, 31, + 91, 248, 0, 6, 16, 8, 110, 0, 2, 158, 5, 15, 248, 0, 29, 84, 101, 110, 97, 98, 108, + 202, 19, 0, 120, 0, 38, 187, 144, 216, 1, 32, 107, 113, 120, 0, 65, 182, 0, 71, 224, + 88, 3, 16, 20, 216, 1, 2, 88, 3, 17, 11, 94, 4, 81, 3, 0, 2, 4, 2, 62, 16, 17, 20, 88, + 17, 16, 24, 134, 52, 33, 4, 26, 62, 16, 16, 29, 90, 52, 33, 4, 30, 12, 0, 17, 33, 12, + 0, 4, 86, 16, 81, 1, 0, 34, 4, 38, 12, 0, 17, 41, 24, 0, 17, 42, 12, 0, 17, 45, 12, 0, + 17, 46, 12, 0, 17, 49, 12, 0, 17, 50, 12, 0, 33, 53, 0, 64, 3, 112, 82, 77, 0, 95, 100, + 105, 115, 173, 0, 32, 66, 121, 120, 16, 0, 35, 2, 16, 42, 9, 0, 15, 4, 0, 6, 2, 168, 2, + 8, 208, 0, 47, 147, 126, 208, 0, 29, 0, 172, 0, 17, 25, 136, 0, 17, 28, 220, 0, 15, + 208, 0, 75, 0, 203, 0, 15, 212, 0, 7, 2, 208, 0, 8, 240, 18, 32, 18, 149, 208, 0, 15, + 240, 18, 243, 8, 232, 1, 32, 21, 178, 24, 1, 31, 183, 184, 2, 10, 0, 150, 17, 6, 184, + 2, 8, 232, 1, 0, 12, 0, 17, 29, 24, 0, 17, 33, 244, 1, 17, 35, 244, 1, 17, 38, 148, 2, + 17, 39, 12, 0, 17, 42, 12, 0, 17, 43, 12, 0, 17, 46, 12, 0, 17, 47, 12, 0, 17, 50, 12, + 0, 17, 51, 12, 0, 31, 54, 184, 2, 8, 1, 227, 1, 15, 193, 2, 7, 5, 0, 15, 19, 208, 168, + 62, 2, 158, 3, 6, 5, 0, 31, 192, 16, 31, 0, 8, 24, 2, 32, 33, 201, 0, 1, 65, 46, 1, + 202, 226, 184, 3, 1, 8, 21, 25, 5, 8, 21, 243, 7, 5, 0, 42, 0, 34, 4, 47, 0, 213, 0, 2, + 4, 122, 4, 0, 0, 100, 97, 116, 97, 0, 39, 97, 3, 255, 18, 45, 116, 114, 97, 110, 115, + 112, 111, 114, 116, 45, 114, 109, 39, 32, 112, 114, 111, 112, 101, 114, 116, 121, 32, + 110, 111, 116, 32, 102, 111, 117, 110, 100, 45, 21, 163, 145, 82, 101, 115, 116, 114, + 105, 99, 116, 101, 114, 6, 9, 41, 5, 3, 59, 21, 0, 0, 5, 38, 100, 132, 0, 5, 32, 31, + 218, 72, 1, 50, 64, 0, 8, 72, 1, 1, 192, 20, 2, 0, 5, 19, 29, 24, 2, 1, 222, 9, 32, 0, + 95, 15, 25, 18, 68, 61, 1, 240, 1, 100, 66, 121, 79, 83, 69, 110, 118, 105, 114, 111, + 110, 109, 101, 110, 116, 236, 1, 0, 88, 0, 8, 160, 2, 32, 138, 228, 88, 0, 15, 160, 2, + 49, 0, 172, 2, 4, 88, 5, 31, 2, 160, 2, 63, 0, 189, 0, 14, 145, 4, 1, 136, 4, 23, 159, + 40, 1, 32, 232, 237, 208, 0, 65, 90, 0, 57, 238, 112, 2, 1, 0, 8, 2, 40, 1, 17, 19, 88, + 3, 0, 6, 8, 0, 189, 2, 3, 46, 1, 193, 112, 117, 98, 108, 105, 115, 104, 73, 79, 82, + 101, 115, 36, 23, 2, 103, 22, 58, 85, 83, 66, 163, 1, 0, 191, 64, 96, 82, 101, 97, 115, + 111, 110, 61, 0, 3, 40, 21, 38, 103, 135, 160, 1, 172, 26, 2, 145, 35, 0, 0, 74, 0, 98, + 228, 120, 0, 0, 144, 24, 51, 24, 0, 18, 126, 8, 3, 120, 0, 114, 109, 97, 112, 65, 110, + 100, 80, 126, 0, 145, 84, 82, 77, 0, 84, 82, 77, 95, 80, 225, 8, 3, 137, 7, 2, 103, 0, + 1, 224, 0, 23, 221, 104, 0, 32, 7, 12, 104, 0, 50, 92, 0, 253, 104, 0, 1, 80, 3, 2, + 224, 0, 2, 104, 0, 0, 108, 11, 58, 41, 0, 13, 230, 0, 15, 110, 0, 8, 3, 213, 0, 53, 85, + 110, 114, 147, 2, 1, 121, 0, 0, 120, 0, 38, 187, 137, 224, 0, 32, 243, 25, 120, 0, 65, + 131, 0, 208, 232, 224, 0, 24, 17, 120, 0, 4, 122, 7, 17, 24, 30, 47, 114, 128, 244, 3, + 0, 2, 1, 85, 205, 23, 193, 2, 4, 255, 255, 255, 255, 2, 1, 45, 2, 4, 255, 18, 48, 2, 6, + 0, 15, 36, 0, 9, 15, 34, 1, 5, 128, 68, 73, 83, 65, 66, 76, 69, 68, 87, 0, 2, 128, 1, + 23, 164, 88, 24, 32, 159, 41, 160, 0, 64, 65, 0, 216, 121, 248, 9, 17, 3, 248, 1, 4, + 88, 24, 2, 16, 27, 48, 1, 4, 33, 248, 1, 0, 20, 25, 6, 251, 22, 9, 198, 25, 52, 116, + 114, 117, 87, 12, 1, 96, 0, 53, 64, 146, 1, 0, 1, 49, 112, 249, 147, 200, 13, 98, 79, + 25, 252, 2, 128, 255, 128, 0, 8, 64, 26, 161, 222, 46, 148, 35, 0, 0, 55, 0, 167, 127, + 128, 0, 1, 160, 3, 2, 128, 0, 50, 6, 0, 1, 234, 15, 15, 122, 0, 3, 67, 115, 116, 97, + 114, 200, 10, 8, 200, 2, 32, 225, 62, 80, 0, 31, 87, 200, 2, 6, 26, 30, 80, 2, 15, 200, + 2, 21, 5, 93, 2, 0, 224, 0, 38, 3, 222, 224, 1, 32, 25, 133, 112, 0, 79, 55, 0, 190, + 130, 192, 0, 39, 8, 144, 1, 32, 190, 219, 80, 0, 65, 66, 0, 29, 131, 80, 0, 7, 144, 1, + 0, 174, 2, 17, 29, 86, 27, 0, 138, 58, 1, 111, 3, 14, 144, 1, 2, 22, 1, 7, 145, 1, 0, + 120, 28, 38, 154, 103, 40, 29, 179, 187, 8, 149, 35, 0, 0, 46, 0, 154, 33, 134, 160, + 49, 19, 22, 244, 2, 2, 121, 2, 80, 73, 79, 71, 101, 116, 71, 14, 128, 75, 101, 121, 83, + 116, 111, 114, 101, 182, 17, 3, 184, 3, 53, 40, 38, 8, 72, 0, 32, 238, 247, 72, 0, 80, + 129, 0, 122, 44, 129, 216, 2, 16, 13, 168, 0, 81, 14, 0, 34, 4, 14, 64, 7, 17, 15, 6, + 0, 17, 16, 6, 0, 17, 17, 6, 0, 128, 18, 0, 1, 0, 2, 4, 65, 1, 106, 10, 17, 19, 12, 0, + 0, 143, 2, 0, 190, 7, 0, 0, 5, 208, 21, 0, 12, 0, 34, 4, 33, 0, 9, 0, 34, 4, 42, 118, + 7, 0, 222, 0, 4, 130, 0, 0, 41, 0, 0, 3, 0, 3, 165, 53, 0, 152, 53, 144, 0, 49, 56, 58, + 50, 54, 58, 49, 51, 24, 0, 1, 4, 0, 0, 152, 1, 38, 177, 39, 160, 0, 161, 1, 218, 151, + 35, 0, 0, 102, 0, 10, 50, 160, 0, 31, 12, 160, 0, 19, 31, 235, 160, 0, 2, 2, 26, 1, 63, + 34, 4, 21, 154, 0, 5, 3, 32, 1, 38, 3, 40, 128, 0, 34, 34, 226, 128, 0, 47, 54, 52, + 128, 0, 25, 47, 33, 2, 32, 1, 1, 15, 128, 0, 21, 53, 216, 98, 0, 128, 0, 32, 83, 249, + 128, 0, 80, 35, 0, 194, 124, 151, 128, 0, 1, 24, 15, 114, 9, 0, 34, 4, 9, 0, 6, 171, 5, + 51, 83, 83, 69, 46, 2, 0, 63, 1, 1, 152, 3, 38, 212, 97, 64, 0, 161, 26, 99, 152, 35, + 0, 0, 189, 0, 43, 129, 64, 0, 3, 48, 5, 10, 136, 29, 0, 186, 1, 117, 7, 0, 140, 0, 2, + 4, 47, 136, 29, 15, 133, 29, 77, 50, 83, 83, 69, 86, 29, 213, 83, 83, 69, 45, 50, 49, + 50, 46, 49, 50, 48, 46, 49, 19, 0, 5, 9, 0, 3, 15, 8, 1, 216, 0, 38, 21, 100, 216, 0, + 161, 172, 23, 153, 35, 0, 0, 41, 0, 170, 127, 216, 0, 1, 112, 4, 4, 24, 1, 3, 184, 19, + 0, 124, 2, 11, 30, 1, 2, 224, 1, 38, 150, 88, 72, 0, 32, 164, 69, 72, 0, 80, 70, 0, + 162, 253, 182, 72, 0, 1, 96, 1, 80, 50, 0, 2, 4, 105, 10, 1, 244, 2, 105, 114, 116, + 117, 97, 108, 32, 98, 111, 111, 108, 32, 67, 111, 114, 101, 65, 10, 16, 81, 72, 117, + 98, 58, 58, 118, 1, 51, 40, 73, 79, 244, 29, 32, 32, 42, 172, 36, 0, 168, 0, 38, 64, + 104, 96, 0, 34, 117, 89, 96, 0, 31, 204, 96, 0, 56, 53, 176, 47, 9, 96, 0, 49, 220, + 104, 156, 152, 5, 53, 237, 44, 139, 152, 5, 38, 0, 93, 128, 0, 34, 131, 203, 32, 0, 51, + 200, 26, 154, 32, 0, 130, 2, 0, 240, 234, 159, 0, 117, 0, 1, 0, 226, 148, 212, 158, 35, + 0, 0, 28, 0, 16, 218, 132, 0, 1, 3, 66, 21, 17, 1, 168, 2, 6, 36, 2, 0, 41, 0, 0, 128, + 4, 8, 56, 0, 47, 182, 224, 56, 0, 21, 112, 8, 0, 45, 20, 6, 0, 121, 69, 0, 224, 0, 0, + 0, 160, 168, 160, 35, 0, 0, 34, 0, 101, 168, 51, 112, 1, 18, 3, 20, 3, 2, 6, 0, 0, 124, + 1, 56, 8, 0, 69, 7, 15, 1, 176, 1, 8, 64, 0, 44, 79, 194, 64, 0, 17, 1, 88, 7, 0, 6, 0, + 15, 64, 0, 3, 85, 2, 0, 125, 86, 144, 128, 0, 226, 216, 41, 163, 35, 0, 0, 42, 0, 196, + 160, 25, 0, 1, 6, 42, 2, 2, 240, 0, 15, 6, 0, 5, 2, 185, 0, 12, 136, 0, 32, 212, 72, + 72, 0, 8, 200, 0, 0, 126, 15, 4, 10, 8, 0, 250, 68, 12, 200, 0, 10, 136, 0, 32, 70, + 155, 64, 0, 6, 136, 0, 0, 62, 0, 15, 130, 0, 5, 2, 24, 0, 1, 135, 0, 13, 16, 1, 32, 90, + 187, 72, 0, 8, 136, 0, 0, 139, 27, 2, 6, 0, 15, 16, 1, 17, 32, 242, 255, 64, 0, 6, 136, + 0, 0, 56, 0, 2, 112, 0, 15, 6, 0, 5, 1, 135, 0, 13, 136, 0, 59, 94, 7, 164, 136, 0, 0, + 63, 0, 2, 6, 0, 15, 136, 0, 17, 32, 21, 73, 64, 0, 6, 136, 0, 0, 56, 0, 15, 130, 0, 5, + 2, 24, 0, 1, 135, 0, 13, 136, 0, 32, 177, 97, 72, 0, 8, 16, 1, 0, 164, 31, 2, 6, 0, 15, + 136, 0, 17, 32, 210, 167, 64, 0, 6, 136, 0, 0, 56, 0, 2, 112, 0, 15, 6, 0, 5, 1, 135, + 0, 13, 136, 0, 32, 199, 174, 72, 0, 8, 136, 0, 0, 100, 33, 2, 6, 0, 15, 136, 0, 17, 32, + 110, 243, 64, 0, 6, 136, 0, 0, 56, 0, 15, 130, 0, 5, 2, 24, 0, 1, 135, 0, 13, 136, 0, + 59, 31, 14, 165, 136, 0, 0, 226, 3, 2, 232, 3, 15, 136, 0, 17, 32, 93, 89, 64, 0, 6, + 136, 0, 0, 62, 0, 2, 112, 0, 15, 6, 0, 5, 1, 135, 0, 1, 136, 0, 53, 23, 5, 1, 160, 58, + 176, 188, 50, 171, 35, 0, 0, 142, 0, 217, 45, 120, 248, 3, 1, 248, 57, 20, 128, 210, + 61, 245, 1, 73, 109, 97, 103, 101, 52, 32, 86, 97, 108, 105, 100, 97, 116, 111, 114, + 220, 61, 48, 51, 46, 49, 219, 61, 50, 87, 101, 100, 219, 61, 172, 51, 32, 50, 51, 58, + 49, 56, 58, 51, 54, 219, 61, 1, 48, 6, 2, 72, 0, 49, 45, 49, 48, 6, 78, 114, 46, 51, + 126, 49, 56, 48, 50, 75, 6, 2, 27, 0, 14, 241, 61, 12, 224, 15, 17, 132, 190, 0, 51, 0, + 0, 242, 8, 0, 14, 224, 15, 112, 4, 2, 247, 222, 185, 9, 168, 177, 3, 243, 1, 0, 0, 0, + 149, 108, 56, 184, 0, 0, 40, 0, 5, 29, 169, 9, 3, 224, 68, 244, 5, 26, 0, 67, 114, 101, + 97, 116, 105, 110, 103, 32, 69, 110, 100, 112, 111, 105, 110, 116, 32, 105, 11, 12, 64, + 0, 113, 237, 102, 225, 185, 0, 0, 44, 64, 0, 19, 4, 64, 0, 179, 30, 0, 67, 108, 117, + 115, 116, 101, 114, 32, 101, 63, 0, 119, 115, 32, 97, 114, 101, 32, 101, 82, 4, 12, 72, + 0, 121, 70, 61, 234, 185, 0, 0, 81, 72, 0, 208, 67, 0, 91, 48, 120, 51, 52, 51, 52, 93, + 32, 85, 115, 142, 0, 160, 105, 110, 116, 101, 114, 110, 97, 108, 32, 108, 103, 74, 5, + 94, 0, 211, 32, 115, 116, 114, 97, 116, 101, 103, 121, 32, 102, 111, 114, 28, 0, 131, + 112, 108, 97, 121, 98, 97, 99, 107, 7, 1, 1, 144, 80, 8, 248, 0, 113, 191, 105, 63, + 187, 0, 0, 70, 112, 0, 19, 5, 184, 0, 18, 56, 248, 0, 243, 4, 101, 32, 39, 65, 80, 66, + 111, 110, 106, 111, 117, 114, 66, 114, 111, 119, 115, 101, 114, 14, 0, 241, 9, 71, 101, + 110, 101, 114, 97, 108, 65, 105, 114, 80, 108, 97, 121, 39, 44, 32, 48, 120, 48, 32, + 60, 32, 62, 96, 6, 10, 24, 1, 32, 108, 140, 96, 0, 25, 68, 96, 0, 31, 54, 96, 0, 13, 1, + 62, 75, 15, 94, 0, 1, 14, 96, 0, 32, 86, 150, 96, 0, 25, 67, 96, 0, 31, 53, 96, 0, 13, + 3, 192, 0, 73, 82, 65, 79, 80, 189, 0, 15, 192, 0, 0, 32, 255, 159, 96, 0, 25, 65, 96, + 0, 31, 51, 96, 0, 13, 1, 192, 0, 15, 94, 0, 1, 14, 96, 0, 32, 111, 168, 96, 0, 25, 74, + 96, 0, 31, 60, 96, 0, 13, 3, 27, 1, 188, 80, 50, 80, 70, 111, 114, 73, 110, 102, 114, + 97, 199, 0, 13, 104, 0, 32, 43, 190, 104, 0, 17, 29, 104, 0, 19, 6, 232, 1, 136, 15, 0, + 80, 50, 80, 32, 105, 115, 145, 2, 12, 56, 0, 121, 58, 32, 65, 187, 0, 0, 43, 56, 0, 35, + 29, 0, 8, 2, 19, 32, 199, 26, 0, 183, 10, 35, 58, 32, 150, 0, 2, 105, 2, 4, 72, 0, 19, + 207, 96, 3, 113, 245, 171, 2, 188, 0, 0, 35, 72, 0, 19, 7, 128, 0, 81, 21, 0, 71, 101, + 116, 95, 3, 33, 112, 97, 7, 43, 81, 112, 101, 101, 114, 115, 63, 0, 118, 0, 2, 1, 4, 0, + 240, 221, 64, 0, 64, 198, 46, 64, 188, 240, 62, 16, 144, 33, 8, 97, 0, 0, 128, 13, 224, + 162, 66, 64, 12, 104, 0, 113, 162, 166, 194, 188, 0, 0, 25, 104, 0, 19, 8, 104, 0, 33, + 11, 0, 51, 81, 1, 202, 3, 0, 52, 0, 0, 3, 0, 49, 4, 0, 5, 168, 2, 4, 96, 0, 64, 31, + 147, 248, 188, 248, 14, 4, 96, 0, 0, 8, 4, 19, 9, 64, 0, 16, 33, 168, 0, 17, 80, 163, + 0, 16, 80, 162, 0, 240, 1, 32, 48, 120, 52, 32, 60, 32, 80, 101, 114, 68, 101, 118, + 105, 99, 101, 249, 2, 4, 136, 0, 4, 80, 4, 113, 146, 34, 6, 189, 0, 0, 96, 136, 0, 19, + 10, 72, 0, 16, 82, 200, 3, 97, 54, 48, 49, 54, 93, 32, 89, 4, 83, 101, 100, 32, 65, 80, + 90, 3, 4, 186, 25, 84, 32, 119, 105, 116, 104, 75, 1, 128, 32, 112, 114, 105, 109, 97, + 114, 121, 39, 0, 2, 114, 1, 3, 46, 0, 16, 32, 17, 4, 69, 65, 49, 49, 93, 232, 1, 16, + 155, 241, 7, 116, 0, 0, 0, 71, 142, 96, 189, 136, 4, 4, 0, 1, 96, 30, 0, 78, 101, 116, + 73, 52, 4, 16, 102, 136, 25, 112, 109, 111, 110, 105, 116, 111, 114, 73, 4, 1, 251, 10, + 0, 15, 1, 5, 72, 0, 4, 192, 0, 113, 33, 141, 164, 189, 0, 0, 105, 192, 0, 19, 11, 72, + 0, 32, 91, 0, 35, 11, 54, 101, 114, 32, 149, 41, 48, 97, 105, 114, 98, 4, 178, 46, 114, + 101, 99, 101, 105, 118, 101, 114, 46, 115, 69, 11, 241, 1, 115, 58, 32, 97, 100, 100, + 101, 100, 32, 104, 97, 110, 100, 108, 101, 114, 146, 4, 34, 39, 97, 135, 1, 20, 101, + 78, 5, 176, 70, 111, 114, 65, 100, 100, 114, 101, 115, 115, 39, 132, 0, 0, 4, 0, 4, + 136, 0, 4, 208, 0, 113, 225, 156, 196, 189, 0, 0, 23, 136, 0, 19, 12, 152, 5, 20, 9, + 208, 1, 22, 101, 80, 3, 4, 48, 0, 64, 194, 36, 197, 189, 184, 28, 0, 192, 1, 4, 48, 0, + 61, 17, 0, 77, 243, 0, 12, 0, 2, 127, 26, 211, 206, 189, 0, 0, 66, 0, 2, 2, 240, 4, 44, + 0, 35, 35, 35, 32, 84, 97, 114, 103, 101, 116, 85, 115, 101, 114, 83, 101, 115, 214, 6, + 240, 7, 44, 32, 98, 117, 116, 32, 110, 111, 32, 99, 111, 110, 115, 111, 108, 101, 32, + 117, 115, 101, 114, 63, 197, 0, 7, 200, 0, 4, 80, 1, 113, 104, 239, 230, 189, 0, 0, + 108, 200, 0, 4, 80, 1, 31, 94, 80, 1, 45, 97, 117, 112, 100, 97, 116, 101, 110, 4, 4, + 83, 1, 96, 65, 117, 116, 104, 83, 116, 221, 1, 2, 83, 1, 4, 80, 1, 4, 136, 0, 121, 35, + 21, 231, 189, 0, 0, 98, 136, 0, 31, 84, 136, 0, 56, 130, 73, 110, 102, 111, 68, 105, + 99, 116, 126, 0, 6, 8, 1, 4, 104, 3, 64, 64, 113, 255, 189, 0, 77, 0, 160, 1, 4, 160, + 2, 21, 10, 208, 1, 29, 100, 48, 0, 68, 44, 35, 0, 190, 128, 4, 4, 144, 3, 17, 29, 144, + 1, 96, 85, 110, 101, 120, 112, 101, 124, 22, 144, 108, 121, 32, 105, 110, 118, 97, 108, + 105, 14, 1, 5, 120, 27, 2, 136, 6, 4, 120, 0, 32, 32, 48, 72, 0, 17, 26, 248, 0, 4, 72, + 0, 60, 12, 0, 73, 55, 0, 1, 192, 72, 0, 32, 7, 4, 56, 0, 64, 227, 144, 95, 190, 16, 21, + 8, 24, 2, 4, 192, 4, 17, 52, 136, 0, 57, 71, 101, 116, 192, 4, 3, 63, 88, 178, 58, 32, + 78, 83, 88, 80, 67, 67, 111, 110, 110, 107, 30, 3, 108, 0, 2, 159, 0, 13, 128, 2, 32, + 3, 188, 104, 0, 25, 40, 128, 2, 4, 104, 0, 48, 18, 0, 83, 168, 3, 197, 32, 114, 101, + 116, 114, 121, 32, 116, 105, 109, 101, 114, 40, 1, 4, 248, 2, 113, 90, 188, 188, 190, + 0, 0, 104, 224, 0, 4, 88, 1, 26, 90, 248, 3, 228, 105, 110, 105, 116, 105, 97, 108, 58, + 32, 70, 108, 97, 103, 115, 180, 7, 242, 6, 44, 32, 73, 80, 118, 52, 32, 60, 60, 32, 65, + 70, 95, 85, 78, 83, 80, 69, 67, 32, 62, 22, 0, 30, 54, 22, 0, 178, 83, 105, 103, 32, + 78, 85, 76, 76, 0, 4, 16, 96, 1, 4, 128, 0, 113, 190, 163, 103, 192, 0, 0, 84, 128, 0, + 19, 15, 128, 0, 84, 70, 0, 95, 65, 80, 1, 1, 241, 13, 118, 105, 116, 121, 72, 101, 108, + 112, 101, 114, 80, 101, 114, 102, 111, 114, 109, 84, 114, 97, 102, 102, 105, 99, 82, + 101, 103, 105, 184, 8, 240, 0, 105, 111, 110, 58, 50, 53, 54, 51, 58, 32, 102, 97, 108, + 115, 101, 86, 3, 32, 100, 105, 191, 85, 1, 49, 1, 12, 240, 0, 32, 19, 196, 112, 0, 17, + 182, 112, 0, 19, 16, 112, 0, 84, 168, 0, 65, 80, 84, 104, 25, 11, 95, 0, 97, 114, 58, + 32, 68, 101, 114, 108, 0, 37, 101, 114, 96, 5, 18, 116, 37, 0, 1, 158, 4, 250, 0, 65, + 87, 68, 76, 32, 97, 116, 32, 77, 65, 67, 32, 48, 48, 58, 3, 0, 2, 151, 5, 17, 116, 3, + 4, 240, 1, 32, 105, 110, 102, 114, 97, 32, 110, 111, 110, 32, 99, 114, 105, 116, 105, + 131, 9, 0, 24, 6, 81, 73, 110, 100, 105, 99, 78, 33, 51, 61, 48, 32, 8, 5, 0, 43, 88, + 19, 61, 37, 5, 144, 32, 101, 114, 114, 61, 45, 54, 55, 54, 90, 39, 12, 64, 1, 32, 10, + 212, 208, 0, 17, 107, 208, 0, 4, 64, 1, 35, 93, 0, 160, 0, 4, 36, 1, 50, 114, 95, 112, + 60, 1, 0, 172, 0, 11, 225, 0, 0, 42, 1, 144, 58, 55, 57, 50, 58, 32, 103, 111, 116, + 107, 0, 49, 111, 114, 32, 109, 0, 209, 47, 48, 120, 70, 70, 70, 70, 69, 53, 57, 54, 32, + 107, 6, 6, 96, 110, 97, 108, 69, 114, 114, 86, 1, 0, 248, 74, 10, 200, 1, 32, 229, 239, + 136, 0, 25, 102, 136, 0, 30, 88, 136, 0, 84, 114, 101, 115, 101, 116, 151, 0, 0, 123, + 0, 4, 89, 0, 79, 58, 55, 50, 51, 131, 0, 25, 12, 8, 1, 32, 42, 250, 128, 0, 25, 154, + 128, 0, 31, 140, 128, 0, 24, 175, 32, 115, 105, 103, 110, 97, 108, 108, 101, 100, 254, + 0, 11, 47, 58, 32, 44, 2, 10, 1, 224, 0, 35, 32, 114, 120, 1, 0, 225, 0, 3, 215, 3, 0, + 228, 28, 0, 3, 0, 132, 4, 0, 4, 2, 208, 154, 20, 11, 0, 3, 240, 1, 179, 199, 68, 193, + 0, 0, 61, 0, 99, 238, 15, 11, 13, 0, 34, 1, 192, 89, 128, 47, 0, 70, 105, 103, 82, 111, + 117, 120, 8, 3, 56, 12, 147, 71, 101, 116, 83, 104, 97, 114, 101, 100, 16, 0, 212, 95, + 98, 108, 111, 99, 107, 95, 105, 110, 118, 111, 107, 101, 88, 0, 68, 224, 146, 20, 11, + 176, 5, 161, 8, 244, 122, 194, 0, 0, 140, 0, 210, 84, 88, 0, 16, 4, 88, 0, 241, 0, 58, + 0, 66, 4, 58, 0, 37, 0, 66, 4, 95, 0, 13, 0, 66, 192, 13, 13, 106, 0, 243, 5, 67, 111, + 110, 116, 101, 120, 116, 85, 116, 105, 108, 105, 116, 105, 101, 115, 95, 65, 100, 100, + 20, 0, 10, 117, 0, 242, 22, 57, 70, 70, 51, 65, 49, 57, 69, 45, 57, 51, 52, 55, 45, 52, + 52, 66, 69, 45, 57, 57, 57, 57, 45, 51, 53, 50, 55, 54, 57, 51, 69, 66, 68, 52, 50, 0, + 69, 20, 96, 32, 65, 117, 100, 105, 111, 167, 0, 1, 128, 4, 38, 96, 155, 168, 0, 64, + 250, 130, 123, 194, 184, 12, 48, 34, 7, 16, 168, 0, 16, 2, 168, 0, 126, 49, 0, 34, 4, + 49, 0, 12, 6, 1, 4, 45, 2, 18, 95, 7, 9, 3, 142, 3, 147, 65, 103, 103, 114, 101, 103, + 97, 116, 101, 110, 0, 66, 77, 117, 115, 105, 13, 45, 3, 112, 1, 0, 152, 5, 4, 24, 1, + 68, 182, 200, 239, 194, 200, 6, 19, 18, 48, 3, 16, 84, 96, 9, 100, 52, 68, 66, 55, 93, + 32, 121, 13, 130, 99, 104, 97, 110, 103, 101, 58, 32, 65, 5, 0, 254, 89, 81, 101, 110, + 105, 110, 103, 241, 3, 1, 51, 35, 3, 178, 3, 86, 32, 102, 114, 111, 109, 73, 13, 112, + 100, 101, 115, 99, 114, 105, 112, 248, 1, 3, 129, 0, 0, 240, 0, 8, 128, 0, 113, 147, + 130, 241, 194, 0, 0, 80, 168, 2, 4, 128, 0, 68, 66, 0, 65, 80, 136, 7, 1, 149, 7, 34, + 32, 99, 231, 9, 16, 58, 176, 9, 2, 153, 0, 35, 40, 101, 33, 0, 22, 68, 99, 0, 1, 31, 0, + 97, 67, 53, 66, 49, 93, 41, 88, 1, 8, 104, 0, 113, 13, 225, 24, 195, 0, 0, 127, 104, 0, + 19, 19, 104, 0, 23, 113, 104, 0, 5, 53, 1, 89, 32, 40, 83, 77, 41, 113, 0, 247, 39, 49, + 56, 57, 69, 93, 44, 32, 117, 117, 105, 100, 58, 32, 97, 55, 97, 101, 51, 48, 57, 100, + 45, 49, 97, 57, 101, 45, 52, 51, 50, 51, 45, 97, 98, 57, 98, 45, 102, 55, 101, 56, 56, + 48, 55, 55, 57, 50, 54, 52, 44, 32, 111, 119, 110, 174, 14, 0, 151, 0, 98, 48, 48, 48, + 48, 93, 46, 128, 1, 38, 160, 216, 240, 1, 176, 107, 189, 46, 195, 0, 0, 102, 0, 36, + 107, 19, 240, 1, 16, 3, 240, 1, 160, 40, 0, 66, 4, 40, 0, 32, 0, 0, 8, 230, 16, 0, 3, + 0, 13, 150, 2, 17, 95, 251, 51, 3, 143, 11, 5, 8, 10, 7, 56, 1, 5, 208, 0, 68, 45, 83, + 77, 45, 197, 0, 0, 172, 16, 16, 96, 80, 0, 63, 0, 0, 248, 192, 31, 4, 80, 232, 15, 0, + 16, 0, 243, 94, 2, 39, 0, 1, 232, 20, 82, 64, 249, 159, 0, 117, 15, 0, 80, 0, 113, 85, + 54, 39, 224, 11, 66, 225, 204, 133, 0, 198, 52, 17, 10, 182, 52, 0, 8, 75, 0, 83, 0, 2, + 242, 19, 147, 2, 4, 100, 0, 2, 0, 79, 70, 70, 247, 74, 35, 79, 78, 9, 0, 1, 80, 0, 38, + 0, 233, 80, 0, 32, 249, 167, 80, 0, 98, 45, 0, 205, 223, 132, 0, 254, 74, 194, 33, 0, + 107, 73, 79, 77, 101, 115, 115, 97, 103, 101, 47, 3, 80, 67, 97, 112, 97, 98, 127, 3, + 18, 121, 133, 37, 0, 139, 0, 0, 72, 0, 23, 48, 72, 0, 32, 147, 172, 72, 0, 132, 24, 0, + 191, 222, 132, 0, 0, 3, 140, 0, 2, 6, 0, 0, 115, 8, 1, 48, 0, 22, 251, 120, 0, 32, 254, + 177, 48, 0, 91, 12, 0, 27, 228, 133, 248, 75, 112, 8, 0, 238, 225, 4, 0, 114, 101, 0, + 112, 0, 0, 0, 69, 64, 56, 39, 216, 15, 32, 187, 175, 184, 26, 32, 2, 2, 168, 17, 2, + 200, 27, 18, 27, 112, 24, 14, 172, 26, 21, 112, 5, 76, 50, 68, 105, 100, 178, 0, 51, + 84, 111, 71, 83, 9, 147, 4, 0, 8, 0, 236, 237, 4, 0, 145, 96, 0, 32, 30, 212, 96, 0, + 65, 66, 0, 38, 206, 96, 0, 22, 3, 96, 0, 19, 17, 46, 20, 1, 202, 17, 14, 102, 0, 2, 17, + 12, 84, 69, 118, 101, 110, 116, 92, 0, 0, 83, 0, 0, 232, 0, 8, 96, 1, 63, 40, 19, 57, + 96, 1, 50, 32, 202, 22, 72, 0, 15, 96, 1, 3, 0, 75, 4, 0, 120, 0, 38, 208, 231, 96, 1, + 32, 91, 46, 48, 0, 83, 37, 0, 31, 68, 132, 136, 56, 4, 40, 2, 15, 22, 2, 1, 0, 24, 3, + 70, 2, 0, 160, 218, 64, 0, 34, 105, 75, 64, 0, 47, 4, 72, 64, 0, 23, 8, 168, 2, 32, + 237, 90, 64, 0, 23, 54, 168, 2, 2, 14, 25, 12, 168, 2, 54, 1, 0, 1, 158, 77, 6, 167, 2, + 13, 144, 0, 32, 181, 94, 80, 0, 23, 36, 144, 0, 4, 80, 0, 5, 53, 0, 5, 9, 0, 4, 136, 1, + 8, 144, 0, 32, 60, 102, 64, 0, 15, 144, 0, 15, 63, 100, 0, 3, 144, 0, 18, 32, 224, 104, + 80, 0, 15, 144, 0, 39, 32, 24, 237, 64, 0, 15, 144, 0, 17, 31, 4, 144, 0, 18, 32, 202, + 241, 80, 0, 15, 144, 0, 39, 63, 117, 113, 59, 144, 0, 13, 18, 3, 88, 4, 31, 5, 144, 0, + 18, 32, 144, 124, 80, 0, 15, 144, 0, 39, 32, 255, 128, 64, 0, 15, 32, 1, 10, 3, 144, 0, + 31, 6, 144, 0, 18, 32, 133, 134, 80, 0, 15, 144, 0, 39, 32, 37, 144, 64, 0, 15, 144, 0, + 10, 1, 236, 4, 63, 100, 0, 7, 144, 0, 18, 32, 60, 147, 80, 0, 15, 144, 0, 25, 70, 8, 0, + 128, 151, 0, 33, 64, 6, 197, 61, 39, 214, 25, 36, 30, 34, 0, 33, 112, 2, 0, 38, 241, + 144, 0, 122, 253, 2, 112, 0, 0, 0, 173, 103, 87, 39, 0, 83, 49, 64, 247, 27, 0, 82, 0, + 132, 5, 2, 94, 26, 2, 33, 0, 0, 96, 3, 0, 48, 0, 17, 123, 14, 0, 89, 0, 0, 28, 189, + 111, 48, 0, 0, 84, 4, 2, 76, 6, 2, 33, 0, 4, 48, 0, 17, 124, 14, 0, 89, 0, 0, 144, 233, + 133, 48, 0, 0, 63, 10, 2, 230, 25, 2, 33, 0, 4, 48, 0, 17, 125, 14, 0, 89, 0, 0, 117, + 55, 158, 48, 0, 0, 237, 9, 2, 96, 5, 2, 33, 0, 4, 48, 0, 17, 126, 14, 0, 89, 0, 0, 176, + 189, 182, 48, 0, 0, 248, 24, 2, 54, 25, 2, 33, 0, 4, 48, 0, 17, 127, 14, 0, 89, 0, 0, + 85, 140, 210, 48, 0, 0, 186, 7, 2, 222, 24, 2, 33, 0, 4, 48, 0, 17, 128, 14, 0, 89, 0, + 0, 105, 86, 232, 48, 0, 17, 7, 48, 0, 0, 6, 0, 2, 3, 0, 0, 40, 6, 81, 90, 30, 0, 0, + 175, 14, 0, 240, 1, 0, 0, 189, 248, 242, 39, 0, 0, 26, 0, 33, 243, 60, 1, 128, 255, + 226, 6, 17, 32, 50, 0, 0, 128, 102, 51, 2, 4, 87, 38, 0, 0, 72, 5, 115, 8, 0, 179, 9, + 6, 0, 113, 18, 0, 64, 75, 97, 18, 40, 224, 27, 33, 35, 80, 96, 28, 16, 4, 96, 6, 0, + 224, 30, 0, 248, 4, 49, 34, 4, 2, 76, 40, 32, 6, 0, 14, 1, 115, 32, 83, 52, 0, 32, 83, + 53, 56, 0, 0, 176, 0, 53, 80, 218, 159, 72, 0, 32, 145, 103, 72, 0, 134, 12, 0, 38, 92, + 132, 0, 0, 1, 202, 1, 0, 40, 0, 8, 8, 29, 79, 78, 231, 19, 40, 64, 29, 21, 8, 32, 5, + 32, 242, 254, 56, 0, 15, 224, 2, 10, 3, 112, 3, 31, 8, 224, 2, 6, 8, 224, 7, 49, 244, + 14, 20, 176, 0, 14, 224, 7, 10, 104, 6, 32, 162, 25, 40, 0, 15, 8, 3, 27, 38, 112, 14, + 96, 1, 121, 177, 226, 78, 40, 0, 0, 27, 16, 65, 17, 13, 224, 64, 98, 32, 69, 114, 114, + 111, 114, 198, 83, 2, 152, 1, 8, 56, 0, 34, 16, 229, 56, 0, 8, 0, 64, 15, 56, 0, 17, + 32, 63, 233, 56, 0, 25, 21, 112, 0, 128, 7, 0, 91, 80, 83, 84, 65, 93, 187, 1, 0, 56, + 2, 8, 104, 0, 34, 81, 234, 48, 0, 8, 104, 0, 15, 48, 0, 9, 32, 198, 237, 48, 0, 25, 54, + 96, 0, 48, 40, 0, 32, 128, 15, 32, 115, 112, 246, 20, 67, 108, 111, 111, 107, 220, 105, + 255, 2, 117, 114, 101, 44, 32, 65, 69, 95, 78, 79, 84, 95, 70, 79, 85, 78, 68, 128, 0, + 0, 34, 125, 239, 80, 0, 8, 128, 0, 15, 80, 0, 41, 32, 36, 244, 80, 0, 25, 38, 160, 0, + 240, 9, 24, 0, 32, 40, 50, 48, 49, 54, 48, 57, 51, 48, 47, 112, 115, 97, 114, 103, 115, + 45, 52, 54, 51, 41, 100, 14, 12, 16, 1, 34, 98, 246, 64, 0, 8, 144, 0, 15, 64, 0, 25, + 121, 246, 24, 79, 40, 0, 0, 37, 128, 0, 48, 23, 0, 91, 223, 10, 48, 93, 32, 64, 230, + 11, 145, 49, 32, 35, 48, 48, 50, 68, 58, 32, 250, 1, 12, 128, 0, 34, 151, 26, 64, 0, 8, + 128, 0, 15, 64, 0, 25, 32, 240, 40, 64, 0, 25, 16, 128, 0, 2, 56, 66, 10, 248, 1, 34, + 71, 43, 40, 0, 8, 104, 0, 15, 40, 0, 1, 32, 223, 47, 40, 0, 25, 68, 80, 0, 82, 54, 0, + 78, 111, 32, 121, 13, 4, 250, 62, 2, 113, 27, 3, 250, 18, 65, 105, 122, 101, 100, 250, + 13, 114, 109, 101, 116, 104, 111, 100, 32, 254, 0, 0, 110, 1, 14, 232, 2, 34, 137, 50, + 96, 0, 8, 136, 0, 15, 96, 0, 57, 32, 66, 54, 96, 0, 15, 16, 1, 15, 34, 198, 55, 40, 0, + 8, 136, 0, 15, 16, 1, 1, 32, 71, 59, 40, 0, 25, 62, 80, 0, 16, 48, 176, 0, 143, 65, + 114, 103, 117, 109, 101, 110, 116, 10, 1, 20, 12, 248, 1, 34, 164, 61, 88, 0, 8, 128, + 0, 15, 88, 0, 49, 32, 219, 64, 88, 0, 15, 0, 1, 15, 34, 93, 66, 40, 0, 8, 128, 0, 15, + 0, 1, 1, 32, 202, 70, 40, 0, 15, 208, 4, 31, 34, 241, 71, 56, 0, 8, 96, 0, 15, 208, 4, + 17, 32, 216, 75, 56, 0, 25, 45, 112, 0, 50, 31, 0, 77, 89, 2, 176, 112, 97, 114, 115, + 101, 47, 101, 120, 101, 99, 117, 67, 16, 3, 59, 18, 15, 88, 3, 2, 34, 88, 77, 72, 0, 8, + 128, 0, 15, 72, 0, 33, 32, 113, 82, 72, 0, 25, 65, 144, 0, 242, 8, 51, 0, 91, 92, 95, + 83, 66, 46, 80, 67, 73, 48, 46, 80, 50, 80, 48, 46, 83, 49, 70, 48, 46, 244, 3, 32, 40, + 78, 128, 52, 17, 102, 1, 0, 149, 57, 51, 53, 49, 50, 99, 99, 52, 50, 119, 84, 13, 16, + 3, 34, 84, 84, 96, 0, 8, 168, 0, 15, 96, 0, 57, 32, 199, 87, 96, 0, 25, 29, 192, 0, 45, + 15, 0, 167, 5, 5, 8, 16, 16, 16, 238, 15, 2, 11, 0, 10, 5, 0, 28, 16, 8, 16, 10, 96, 4, + 34, 128, 89, 104, 0, 8, 200, 0, 15, 104, 0, 1, 12, 0, 1, 32, 129, 95, 56, 0, 25, 39, + 160, 0, 26, 25, 128, 5, 1, 246, 1, 64, 45, 54, 51, 50, 193, 5, 12, 64, 0, 34, 126, 97, + 64, 0, 8, 120, 0, 15, 64, 0, 25, 32, 211, 177, 64, 0, 15, 224, 2, 31, 34, 30, 179, 56, + 0, 8, 120, 0, 15, 224, 2, 17, 32, 177, 181, 56, 0, 15, 176, 7, 23, 34, 173, 182, 48, 0, + 8, 104, 0, 15, 176, 7, 9, 32, 120, 185, 48, 0, 15, 176, 7, 55, 34, 44, 187, 80, 0, 8, + 128, 0, 15, 176, 7, 41, 32, 45, 191, 80, 0, 15, 176, 7, 39, 34, 40, 193, 64, 0, 8, 144, + 0, 15, 176, 7, 25, 32, 145, 199, 64, 0, 15, 176, 7, 39, 34, 228, 200, 64, 0, 8, 128, 0, + 15, 176, 7, 25, 32, 42, 203, 64, 0, 15, 160, 5, 15, 34, 180, 204, 40, 0, 8, 104, 0, 15, + 160, 5, 1, 32, 8, 208, 40, 0, 15, 176, 7, 71, 34, 165, 210, 96, 0, 8, 136, 0, 15, 176, + 7, 57, 32, 10, 214, 96, 0, 15, 16, 1, 15, 34, 144, 215, 40, 0, 8, 136, 0, 15, 16, 1, 1, + 32, 170, 218, 40, 0, 15, 176, 7, 63, 34, 18, 221, 88, 0, 8, 128, 0, 15, 176, 7, 49, 32, + 46, 224, 88, 0, 15, 0, 1, 15, 34, 172, 225, 40, 0, 8, 128, 0, 15, 0, 1, 1, 32, 181, + 228, 40, 0, 15, 208, 4, 31, 34, 209, 229, 56, 0, 8, 96, 0, 15, 208, 4, 17, 32, 202, + 232, 56, 0, 15, 176, 7, 47, 34, 78, 234, 72, 0, 8, 128, 0, 15, 176, 7, 33, 32, 236, + 238, 72, 0, 15, 176, 7, 71, 34, 185, 240, 96, 0, 8, 168, 0, 15, 176, 7, 57, 32, 6, 244, + 96, 0, 15, 176, 7, 15, 12, 8, 7, 34, 54, 245, 56, 0, 8, 152, 0, 15, 128, 7, 17, 32, 96, + 248, 56, 0, 15, 128, 7, 39, 34, 102, 250, 64, 0, 8, 120, 0, 15, 128, 7, 25, 49, 78, 42, + 80, 120, 2, 15, 48, 15, 29, 34, 156, 43, 56, 0, 8, 120, 0, 15, 176, 2, 17, 32, 217, 45, + 56, 0, 15, 128, 7, 23, 34, 219, 46, 48, 0, 8, 104, 0, 15, 128, 7, 9, 32, 109, 49, 48, + 0, 15, 128, 7, 55, 34, 151, 64, 80, 0, 8, 128, 0, 15, 128, 7, 41, 32, 110, 70, 80, 0, + 15, 128, 7, 39, 34, 45, 73, 64, 0, 8, 144, 0, 15, 128, 7, 25, 32, 178, 80, 64, 0, 15, + 128, 7, 39, 34, 34, 82, 64, 0, 8, 128, 0, 15, 128, 7, 25, 32, 125, 84, 64, 0, 15, 112, + 5, 15, 34, 59, 86, 40, 0, 8, 104, 0, 15, 112, 5, 1, 32, 220, 89, 40, 0, 15, 128, 7, 71, + 34, 94, 92, 96, 0, 8, 136, 0, 15, 128, 7, 57, 32, 176, 95, 96, 0, 15, 16, 1, 15, 34, + 52, 97, 40, 0, 8, 136, 0, 15, 16, 1, 1, 32, 103, 100, 40, 0, 15, 128, 7, 63, 34, 196, + 102, 88, 0, 8, 128, 0, 15, 128, 7, 49, 32, 219, 105, 88, 0, 15, 0, 1, 15, 34, 83, 107, + 40, 0, 8, 128, 0, 15, 0, 1, 1, 32, 11, 111, 40, 0, 15, 128, 7, 31, 34, 42, 112, 56, 0, + 8, 96, 0, 15, 208, 4, 17, 32, 36, 115, 56, 0, 15, 128, 7, 47, 34, 156, 116, 72, 0, 8, + 128, 0, 15, 128, 7, 33, 32, 5, 121, 72, 0, 15, 128, 7, 13, 79, 72, 68, 69, 70, 48, 15, + 7, 47, 57, 54, 48, 15, 7, 34, 217, 122, 96, 0, 8, 168, 0, 14, 128, 7, 15, 96, 0, 39, + 32, 34, 126, 96, 0, 15, 128, 7, 31, 34, 76, 127, 56, 0, 8, 152, 0, 15, 128, 7, 17, 32, + 121, 130, 56, 0, 15, 128, 7, 39, 34, 128, 132, 64, 0, 8, 120, 0, 15, 128, 7, 25, 32, + 47, 208, 64, 0, 15, 176, 2, 15, 4, 32, 16, 31, 8, 32, 16, 4, 14, 16, 111, 10, 32, 16, + 34, 217, 209, 104, 0, 8, 168, 0, 15, 224, 2, 17, 32, 123, 214, 56, 0, 15, 176, 7, 23, + 34, 132, 215, 48, 0, 8, 104, 0, 15, 176, 7, 9, 32, 38, 218, 48, 0, 15, 176, 7, 55, 34, + 203, 219, 80, 0, 8, 128, 0, 15, 176, 7, 41, 32, 170, 223, 80, 0, 15, 176, 7, 39, 34, + 173, 225, 64, 0, 8, 144, 0, 15, 176, 7, 25, 32, 45, 231, 64, 0, 15, 176, 7, 39, 34, + 129, 232, 64, 0, 8, 128, 0, 15, 176, 7, 25, 32, 123, 234, 64, 0, 15, 160, 5, 15, 34, 1, + 236, 40, 0, 8, 104, 0, 15, 160, 5, 1, 32, 74, 239, 40, 0, 15, 176, 7, 71, 34, 194, 241, + 96, 0, 8, 136, 0, 15, 176, 7, 57, 32, 13, 245, 96, 0, 15, 16, 1, 15, 34, 151, 246, 40, + 0, 8, 136, 0, 15, 16, 1, 1, 32, 188, 249, 40, 0, 15, 176, 7, 63, 34, 30, 252, 88, 0, 8, + 128, 0, 15, 176, 7, 49, 32, 50, 255, 88, 0, 15, 0, 1, 15, 49, 169, 0, 81, 40, 0, 8, + 128, 0, 15, 0, 1, 1, 32, 179, 3, 40, 0, 15, 0, 5, 15, 12, 112, 13, 34, 234, 4, 56, 0, + 8, 96, 0, 15, 208, 4, 17, 32, 177, 7, 56, 0, 25, 45, 112, 0, 15, 104, 7, 33, 34, 51, 9, + 72, 0, 8, 128, 0, 15, 72, 0, 33, 32, 135, 13, 72, 0, 15, 176, 7, 71, 34, 94, 15, 96, 0, + 8, 168, 0, 15, 176, 7, 57, 32, 128, 18, 96, 0, 15, 176, 7, 31, 34, 173, 19, 56, 0, 8, + 152, 0, 15, 176, 7, 17, 32, 188, 22, 56, 0, 15, 176, 7, 39, 34, 192, 24, 64, 0, 8, 120, + 0, 15, 176, 7, 25, 32, 193, 74, 64, 0, 15, 176, 2, 31, 34, 5, 76, 56, 0, 8, 120, 0, 15, + 176, 2, 17, 32, 64, 78, 56, 0, 15, 128, 7, 23, 34, 71, 79, 48, 0, 8, 104, 0, 15, 128, + 7, 9, 32, 211, 81, 48, 0, 15, 128, 7, 55, 34, 123, 83, 80, 0, 8, 128, 0, 15, 128, 7, + 41, 32, 95, 87, 80, 0, 15, 128, 7, 39, 34, 88, 89, 64, 0, 8, 144, 0, 15, 128, 7, 25, + 32, 136, 94, 64, 0, 15, 128, 7, 39, 34, 223, 95, 64, 0, 8, 128, 0, 15, 128, 7, 25, 32, + 222, 97, 64, 0, 15, 112, 5, 15, 34, 100, 99, 40, 0, 8, 104, 0, 15, 112, 5, 1, 32, 139, + 102, 40, 0, 15, 128, 7, 71, 34, 6, 105, 96, 0, 8, 136, 0, 15, 128, 7, 57, 32, 84, 108, + 96, 0, 15, 16, 1, 15, 34, 214, 109, 40, 0, 8, 136, 0, 15, 16, 1, 1, 32, 7, 113, 40, 0, + 15, 128, 7, 63, 34, 112, 115, 88, 0, 8, 128, 0, 15, 128, 7, 49, 32, 129, 118, 88, 0, + 15, 0, 1, 15, 34, 2, 120, 40, 0, 8, 128, 0, 15, 0, 1, 1, 32, 224, 122, 40, 0, 15, 208, + 4, 31, 34, 255, 123, 56, 0, 8, 96, 0, 15, 208, 4, 17, 32, 221, 126, 56, 0, 15, 128, 7, + 47, 34, 84, 128, 72, 0, 8, 128, 0, 15, 128, 7, 33, 32, 170, 132, 72, 0, 15, 128, 7, 13, + 47, 83, 51, 96, 30, 9, 47, 48, 102, 48, 15, 7, 34, 126, 134, 96, 0, 8, 168, 0, 14, 128, + 7, 15, 96, 0, 39, 32, 183, 137, 96, 0, 15, 128, 7, 31, 34, 226, 138, 56, 0, 8, 152, 0, + 15, 128, 7, 17, 32, 10, 142, 56, 0, 15, 128, 7, 39, 34, 11, 144, 64, 0, 8, 120, 0, 15, + 128, 7, 25, 32, 105, 207, 64, 0, 15, 176, 2, 31, 34, 166, 208, 56, 0, 8, 120, 0, 15, + 176, 2, 17, 32, 182, 210, 56, 0, 15, 128, 7, 23, 34, 191, 211, 48, 0, 8, 104, 0, 15, + 128, 7, 9, 32, 71, 214, 48, 0, 15, 128, 7, 39, 4, 24, 16, 16, 240, 91, 47, 9, 49, 32, + 2, 12, 0, 31, 224, 24, 16, 12, 34, 33, 216, 128, 0, 8, 176, 0, 15, 176, 7, 41, 32, 104, + 222, 80, 0, 15, 176, 7, 39, 34, 105, 224, 64, 0, 8, 144, 0, 15, 176, 7, 25, 32, 180, + 229, 64, 0, 15, 176, 7, 39, 34, 9, 231, 64, 0, 8, 128, 0, 15, 176, 7, 25, 32, 244, 232, + 64, 0, 15, 160, 5, 15, 34, 126, 234, 40, 0, 8, 104, 0, 15, 160, 5, 1, 32, 178, 237, 40, + 0, 15, 176, 7, 71, 34, 46, 240, 96, 0, 8, 136, 0, 15, 176, 7, 57, 32, 112, 243, 96, 0, + 15, 16, 1, 15, 34, 244, 244, 40, 0, 8, 136, 0, 15, 16, 1, 1, 32, 3, 248, 40, 0, 15, + 176, 7, 63, 34, 105, 250, 88, 0, 8, 128, 0, 15, 176, 7, 49, 32, 189, 253, 88, 0, 15, 0, + 1, 15, 34, 52, 255, 40, 0, 8, 128, 0, 15, 0, 1, 1, 49, 14, 2, 82, 200, 4, 15, 176, 27, + 29, 34, 47, 3, 56, 0, 8, 96, 0, 15, 0, 5, 17, 32, 10, 6, 56, 0, 15, 176, 7, 47, 34, + 129, 7, 72, 0, 8, 128, 0, 15, 176, 7, 33, 32, 251, 11, 72, 0, 15, 176, 7, 71, 34, 208, + 13, 96, 0, 8, 168, 0, 15, 176, 7, 57, 32, 2, 17, 96, 0, 15, 176, 7, 31, 34, 53, 18, 56, + 0, 8, 152, 0, 15, 176, 7, 17, 32, 57, 21, 56, 0, 15, 176, 7, 39, 34, 77, 23, 64, 0, 8, + 120, 0, 15, 176, 7, 25, 32, 72, 143, 64, 0, 15, 176, 7, 31, 34, 162, 144, 56, 0, 8, + 120, 0, 15, 176, 2, 17, 32, 202, 146, 56, 0, 15, 176, 7, 23, 34, 216, 147, 48, 0, 8, + 104, 0, 15, 176, 7, 9, 32, 136, 150, 48, 0, 15, 176, 7, 39, 12, 200, 18, 34, 59, 152, + 80, 0, 8, 128, 0, 15, 128, 7, 41, 32, 23, 156, 80, 0, 15, 128, 7, 39, 34, 32, 158, 64, + 0, 8, 144, 0, 15, 128, 7, 25, 32, 131, 163, 64, 0, 15, 128, 7, 39, 34, 233, 164, 64, 0, + 8, 128, 0, 15, 128, 7, 25, 32, 222, 166, 64, 0, 15, 112, 5, 15, 34, 108, 168, 40, 0, 8, + 104, 0, 15, 112, 5, 1, 32, 184, 171, 40, 0, 15, 128, 7, 71, 34, 75, 174, 96, 0, 8, 136, + 0, 15, 128, 7, 57, 32, 162, 177, 96, 0, 15, 16, 1, 15, 34, 45, 179, 40, 0, 8, 136, 0, + 15, 16, 1, 1, 32, 79, 182, 40, 0, 15, 128, 7, 63, 34, 194, 184, 88, 0, 8, 128, 0, 15, + 128, 7, 49, 32, 233, 187, 88, 0, 15, 0, 1, 15, 34, 112, 189, 40, 0, 8, 128, 0, 15, 0, + 1, 1, 32, 83, 192, 40, 0, 15, 208, 4, 31, 34, 200, 206, 56, 0, 8, 96, 0, 15, 208, 4, + 17, 32, 16, 212, 56, 0, 15, 128, 7, 47, 49, 103, 13, 83, 72, 0, 8, 128, 0, 15, 128, 7, + 33, 32, 191, 18, 72, 0, 15, 128, 7, 14, 31, 52, 48, 15, 9, 47, 57, 99, 48, 15, 7, 34, + 176, 20, 96, 0, 8, 168, 0, 15, 128, 7, 0, 15, 96, 0, 38, 32, 87, 24, 96, 0, 15, 128, 7, + 31, 34, 127, 25, 56, 0, 8, 152, 0, 15, 128, 7, 17, 32, 202, 28, 56, 0, 15, 128, 7, 39, + 34, 74, 31, 64, 0, 8, 120, 0, 15, 128, 7, 25, 32, 124, 241, 64, 0, 15, 176, 2, 31, 34, + 185, 242, 56, 0, 8, 120, 0, 15, 176, 2, 17, 32, 65, 245, 56, 0, 15, 128, 7, 23, 34, 75, + 246, 48, 0, 8, 104, 0, 15, 128, 7, 9, 32, 228, 248, 48, 0, 15, 128, 7, 55, 34, 139, + 250, 80, 0, 8, 128, 0, 15, 128, 7, 41, 32, 101, 254, 80, 0, 15, 128, 7, 39, 49, 187, 0, + 84, 64, 0, 8, 144, 0, 15, 128, 7, 9, 4, 0, 16, 17, 144, 238, 15, 51, 0, 0, 92, 8, 0, + 19, 239, 8, 0, 33, 128, 0, 56, 48, 19, 2, 15, 0, 1, 128, 76, 83, 80, 188, 15, 7, 145, + 18, 0, 64, 55, 174, 163, 196, 128, 76, 0, 167, 62, 113, 0, 0, 0, 128, 219, 35, 14, 245, + 56, 12, 40, 0, 49, 149, 149, 204, 40, 0, 27, 1, 40, 0, 132, 4, 0, 2, 2, 128, 201, 18, + 0, 80, 0, 64, 195, 252, 224, 196, 136, 58, 49, 106, 112, 0, 198, 56, 4, 160, 0, 4, 224, + 64, 19, 172, 137, 0, 16, 90, 129, 58, 15, 224, 64, 0, 0, 120, 0, 80, 32, 74, 56, 0, + 163, 65, 58, 112, 0, 0, 0, 107, 244, 156, 191, 160, 0, 18, 208, 48, 0, 50, 128, 29, + 184, 18, 57, 12, 40, 0, 64, 2, 70, 4, 194, 40, 0, 27, 209, 40, 0, 0, 136, 69, 53, 96, + 69, 128, 80, 0, 64, 34, 182, 140, 194, 48, 54, 68, 139, 235, 72, 0, 192, 76, 130, 23, + 0, 115, 116, 97, 114, 116, 115, 13, 71, 160, 47, 118, 97, 114, 47, 101, 109, 112, 116, + 121, 171, 0, 0, 224, 0, 53, 48, 124, 6, 64, 0, 64, 5, 146, 245, 197, 80, 57, 176, 150, + 204, 0, 0, 20, 0, 0, 2, 0, 8, 14, 39, 0, 0, 4, 0, 32, 8, 13, 6, 0, 3, 3, 0, 12, 56, 0, + 79, 86, 102, 76, 198, 56, 0, 33, 63, 72, 121, 91, 56, 0, 34, 63, 85, 25, 103, 56, 0, + 18, 0, 72, 1, 38, 48, 85, 32, 1, 64, 179, 192, 173, 198, 72, 1, 19, 210, 72, 1, 34, 25, + 143, 250, 75, 12, 40, 0, 49, 150, 149, 177, 40, 0, 27, 211, 40, 0, 0, 248, 0, 38, 28, + 119, 48, 1, 240, 1, 82, 170, 202, 198, 0, 0, 48, 0, 120, 0, 1, 0, 20, 0, 34, 1, 214, + 69, 83, 34, 0, 79, 84, 65, 180, 69, 161, 46, 112, 108, 105, 115, 116, 32, 109, 105, + 115, 2, 82, 129, 99, 104, 101, 99, 107, 45, 105, 110, 168, 2, 8, 8, 2, 49, 73, 121, + 221, 112, 0, 19, 212, 112, 0, 4, 8, 2, 0, 88, 68, 68, 176, 174, 76, 2, 48, 2, 241, 21, + 117, 51, 231, 198, 0, 0, 74, 0, 203, 70, 37, 2, 21, 0, 34, 2, 34, 4, 0, 0, 36, 0, 34, + 4, 36, 0, 18, 0, 47, 112, 114, 105, 118, 97, 116, 101, 226, 1, 65, 112, 114, 111, 116, + 102, 75, 241, 2, 47, 47, 115, 102, 97, 110, 97, 108, 121, 116, 105, 99, 115, 0, 80, + 101, 114, 140, 0, 113, 111, 110, 32, 100, 101, 110, 105, 36, 66, 0, 1, 1, 12, 104, 0, + 166, 12, 213, 233, 198, 0, 0, 111, 0, 251, 69, 104, 0, 95, 73, 0, 34, 4, 73, 104, 0, + 19, 17, 47, 187, 72, 240, 8, 69, 69, 69, 45, 68, 68, 68, 68, 45, 67, 67, 67, 67, 45, + 66, 66, 66, 66, 45, 65, 65, 65, 65, 182, 56, 79, 48, 49, 49, 65, 141, 0, 1, 0, 136, 0, + 38, 112, 78, 240, 0, 176, 168, 84, 15, 199, 0, 0, 112, 1, 233, 57, 34, 136, 0, 113, 1, + 66, 4, 0, 0, 98, 1, 235, 58, 4, 12, 164, 113, 78, 83, 67, 111, 99, 111, 97, 20, 0, 2, + 19, 0, 2, 3, 164, 246, 8, 53, 49, 51, 32, 34, 89, 111, 117, 32, 100, 111, 110, 226, + 128, 153, 116, 32, 104, 97, 118, 101, 32, 112, 1, 1, 64, 116, 111, 32, 115, 19, 0, 64, + 116, 104, 101, 32, 208, 152, 79, 32, 226, 128, 156, 184, 0, 17, 48, 226, 128, 157, 32, + 153, 1, 55, 0, 80, 111, 108, 100, 101, 114, 57, 0, 7, 101, 1, 96, 226, 128, 157, 46, + 34, 32, 114, 78, 128, 73, 110, 102, 111, 61, 123, 78, 83, 255, 122, 95, 80, 97, 116, + 104, 61, 163, 1, 4, 7, 61, 0, 15, 58, 1, 18, 80, 44, 32, 78, 83, 85, 146, 109, 81, 108, + 121, 105, 110, 103, 250, 0, 241, 2, 61, 48, 120, 55, 102, 57, 48, 48, 50, 49, 48, 55, + 100, 49, 48, 32, 123, 22, 0, 6, 36, 1, 81, 80, 79, 83, 73, 88, 20, 0, 2, 19, 0, 2, 36, + 1, 0, 35, 1, 13, 134, 1, 49, 34, 125, 125, 136, 1, 38, 0, 165, 136, 1, 64, 255, 62, 16, + 199, 248, 4, 83, 177, 234, 35, 2, 21, 48, 2, 38, 208, 77, 32, 0, 49, 38, 42, 29, 168, + 1, 47, 28, 29, 168, 1, 255, 23, 79, 49, 51, 102, 50, 168, 1, 50, 8, 136, 1, 63, 88, 62, + 31, 136, 1, 255, 31, 63, 52, 55, 48, 136, 1, 50, 8, 48, 3, 32, 151, 84, 136, 1, 8, 48, + 3, 10, 56, 6, 79, 238, 101, 34, 199, 56, 6, 33, 12, 152, 3, 32, 15, 138, 72, 0, 8, 104, + 0, 10, 16, 2, 63, 139, 171, 36, 16, 2, 255, 31, 63, 53, 51, 97, 16, 2, 50, 8, 136, 1, + 63, 156, 74, 38, 136, 1, 255, 32, 47, 53, 99, 136, 1, 50, 8, 152, 3, 32, 206, 83, 136, + 1, 8, 48, 3, 70, 2, 2, 160, 150, 208, 9, 211, 63, 117, 80, 199, 0, 0, 17, 0, 185, 139, + 2, 0, 23, 208, 9, 53, 3, 0, 54, 33, 101, 12, 184, 9, 64, 210, 15, 88, 199, 80, 10, 31, + 213, 184, 9, 12, 79, 249, 248, 94, 199, 184, 9, 81, 79, 153, 31, 96, 199, 184, 9, 113, + 49, 128, 240, 99, 240, 2, 15, 184, 9, 255, 24, 95, 52, 48, 52, 49, 100, 240, 2, 47, + 131, 16, 5, 2, 160, 72, 105, 33, 187, 48, 12, 147, 116, 77, 66, 200, 0, 0, 174, 0, 160, + 160, 2, 240, 0, 255, 33, 105, 33, 26, 0, 35, 2, 64, 4, 0, 0, 146, 0, 65, 137, 71, 10, + 90, 175, 82, 77, 83, 85, 68, 65, 18, 0, 1, 34, 10, 246, 8, 54, 48, 48, 55, 32, 34, 80, + 97, 116, 104, 32, 115, 121, 109, 98, 111, 108, 32, 114, 101, 115, 111, 108, 33, 65, 58, + 117, 114, 101, 237, 10, 87, 68, 101, 98, 117, 103, 39, 81, 31, 61, 61, 0, 11, 19, 44, + 88, 0, 35, 61, 60, 191, 12, 16, 62, 68, 73, 132, 4, 0, 3, 2, 0, 127, 6, 0, 200, 0, 32, + 175, 140, 200, 0, 21, 26, 200, 0, 194, 127, 57, 1, 0, 25, 0, 0, 1, 0, 8, 119, 23, 234, + 0, 2, 5, 0, 0, 56, 0, 23, 192, 56, 0, 32, 153, 143, 56, 0, 21, 16, 56, 0, 18, 199, 56, + 0, 1, 40, 0, 23, 240, 40, 0, 42, 76, 145, 40, 0, 33, 15, 58, 96, 0, 1, 40, 0, 38, 224, + 126, 136, 0, 42, 82, 151, 40, 0, 34, 37, 56, 40, 0, 4, 8, 16, 19, 48, 40, 16, 17, 180, + 142, 0, 50, 0, 0, 113, 120, 1, 43, 0, 32, 96, 178, 0, 72, 4, 83, 224, 188, 77, 2, 186, + 224, 0, 64, 191, 237, 42, 197, 72, 4, 18, 32, 64, 0, 65, 128, 134, 79, 27, 10, 0, 102, + 4, 0, 5, 2, 0, 210, 40, 0, 64, 6, 62, 43, 197, 243, 16, 4, 40, 0, 65, 99, 82, 27, 2, + 44, 74, 116, 1, 21, 2, 0, 85, 128, 0, 80, 0, 64, 42, 1, 47, 197, 26, 14, 4, 40, 0, 4, + 144, 0, 4, 16, 0, 19, 33, 8, 0, 8, 0, 15, 38, 80, 189, 104, 0, 49, 239, 18, 67, 144, 0, + 19, 34, 40, 0, 49, 179, 87, 62, 10, 0, 0, 144, 0, 38, 128, 122, 40, 0, 117, 18, 173, + 155, 197, 0, 0, 106, 40, 0, 128, 5, 31, 56, 2, 20, 0, 34, 2, 168, 13, 146, 39, 0, 66, + 4, 39, 0, 39, 0, 47, 87, 81, 208, 47, 76, 105, 98, 114, 97, 114, 121, 47, 83, 101, 99, + 117, 7, 136, 240, 37, 47, 108, 100, 97, 112, 100, 108, 46, 98, 117, 110, 100, 108, 101, + 0, 123, 56, 55, 49, 57, 49, 99, 97, 54, 45, 48, 102, 99, 57, 45, 49, 49, 100, 52, 45, + 56, 52, 57, 97, 45, 48, 48, 48, 53, 48, 50, 98, 53, 50, 49, 50, 50, 28, 2, 0, 3, 0, 12, + 136, 0, 127, 123, 82, 157, 197, 0, 0, 113, 136, 0, 2, 95, 46, 0, 66, 4, 46, 136, 0, 0, + 81, 70, 114, 97, 109, 101, 45, 164, 5, 147, 0, 36, 46, 102, 20, 0, 5, 143, 0, 31, 48, + 143, 0, 17, 1, 48, 13, 68, 64, 137, 65, 6, 128, 1, 49, 29, 131, 148, 104, 6, 64, 140, + 78, 64, 6, 3, 2, 0, 32, 0, 23, 96, 32, 0, 49, 151, 16, 152, 32, 0, 34, 216, 99, 32, 0, + 4, 64, 2, 16, 168, 221, 0, 67, 0, 0, 0, 197, 8, 0, 3, 192, 90, 32, 0, 152, 245, 1, 0, + 144, 17, 2, 23, 0, 1, 112, 0, 0, 24, 2, 19, 245, 112, 0, 64, 119, 29, 105, 200, 160, + 13, 6, 16, 2, 32, 4, 0, 16, 2, 4, 32, 0, 64, 228, 16, 109, 200, 96, 2, 19, 128, 168, 1, + 4, 248, 1, 0, 72, 0, 0, 184, 0, 4, 40, 0, 49, 181, 250, 128, 72, 0, 12, 184, 0, 4, 32, + 0, 49, 70, 241, 130, 32, 0, 15, 184, 0, 5, 3, 144, 177, 47, 0, 163, 184, 0, 12, 17, 19, + 122, 4, 111, 0, 0, 107, 167, 172, 202, 184, 0, 1, 4, 32, 0, 64, 116, 84, 176, 202, 184, + 0, 31, 144, 184, 0, 4, 4, 40, 0, 49, 212, 205, 188, 72, 0, 12, 184, 0, 4, 32, 0, 34, + 134, 211, 32, 0, 12, 184, 0, 18, 72, 167, 0, 35, 0, 165, 8, 0, 19, 74, 184, 0, 27, 56, + 112, 1, 0, 176, 3, 0, 80, 1, 19, 129, 8, 1, 64, 156, 155, 85, 205, 152, 0, 27, 224, + 152, 0, 4, 200, 1, 18, 152, 79, 0, 35, 0, 215, 8, 0, 19, 178, 88, 0, 31, 136, 88, 0, 0, + 83, 208, 67, 56, 0, 50, 168, 0, 49, 126, 165, 126, 88, 0, 19, 240, 88, 0, 49, 184, 46, + 54, 65, 0, 0, 128, 0, 38, 160, 69, 40, 0, 49, 7, 186, 158, 40, 0, 3, 96, 179, 54, 128, + 51, 120, 40, 0, 0, 88, 18, 4, 80, 0, 49, 75, 89, 170, 40, 0, 19, 242, 40, 0, 4, 96, 20, + 4, 168, 0, 19, 176, 184, 20, 17, 151, 22, 0, 51, 0, 0, 44, 168, 0, 29, 160, 88, 37, + 115, 4, 2, 160, 97, 7, 0, 54, 0, 1, 211, 107, 60, 161, 206, 0, 0, 77, 0, 188, 105, 5, + 0, 2, 136, 18, 134, 48, 0, 34, 4, 48, 0, 9, 0, 103, 96, 1, 155, 84, 244, 0, 117, 105, + 97, 103, 101, 110, 116, 46, 114, 101, 112, 111, 114, 116, 65, 139, 18, 50, 82, 101, + 112, 165, 101, 21, 0, 21, 19, 3, 40, 3, 38, 176, 100, 104, 0, 161, 45, 51, 183, 206, 0, + 0, 82, 0, 64, 114, 104, 0, 16, 3, 240, 18, 144, 48, 0, 0, 8, 128, 77, 128, 30, 234, 13, + 79, 5, 38, 107, 15, 118, 0, 29, 2, 56, 0, 0, 0, 3, 23, 224, 216, 0, 32, 214, 54, 112, + 0, 79, 87, 0, 12, 116, 112, 0, 3, 15, 226, 0, 45, 0, 112, 0, 8, 72, 1, 32, 172, 182, + 112, 0, 25, 74, 72, 1, 95, 45, 0, 34, 4, 45, 72, 1, 7, 249, 6, 112, 108, 117, 103, 105, + 110, 65, 99, 116, 105, 118, 105, 116, 121, 67, 108, 101, 97, 110, 117, 112, 69, 1, 15, + 72, 1, 0, 32, 167, 198, 104, 0, 25, 79, 72, 1, 111, 45, 0, 0, 8, 80, 73, 72, 1, 20, 15, + 118, 0, 3, 1, 136, 4, 8, 64, 1, 32, 122, 200, 104, 0, 25, 84, 64, 1, 8, 104, 0, 15, + 218, 0, 45, 0, 112, 0, 8, 64, 1, 32, 39, 209, 112, 0, 25, 72, 64, 1, 95, 43, 0, 34, 4, + 43, 64, 1, 7, 240, 0, 116, 117, 110, 101, 77, 76, 84, 104, 114, 101, 115, 104, 111, + 108, 100, 165, 113, 6, 62, 1, 0, 96, 0, 8, 128, 2, 32, 92, 216, 96, 0, 25, 77, 56, 1, + 16, 43, 128, 2, 31, 87, 56, 1, 20, 15, 110, 0, 1, 3, 160, 1, 8, 56, 1, 32, 193, 217, + 104, 0, 25, 82, 56, 1, 8, 104, 0, 15, 210, 0, 39, 1, 231, 2, 1, 168, 1, 8, 56, 1, 32, + 59, 225, 112, 0, 25, 62, 56, 1, 19, 33, 60, 114, 15, 74, 3, 5, 74, 117, 110, 79, 110, + 46, 1, 2, 200, 0, 8, 48, 1, 32, 229, 229, 88, 0, 25, 67, 48, 1, 111, 33, 0, 0, 8, 160, + 89, 104, 2, 20, 6, 102, 0, 5, 184, 0, 8, 40, 1, 32, 33, 231, 96, 0, 25, 72, 40, 1, 8, + 96, 0, 15, 194, 0, 29, 0, 24, 1, 83, 32, 98, 7, 0, 62, 48, 5, 49, 212, 110, 252, 0, 4, + 47, 123, 119, 0, 4, 71, 38, 224, 100, 112, 0, 34, 163, 118, 112, 0, 47, 69, 253, 112, + 0, 71, 0, 224, 0, 19, 61, 224, 0, 49, 139, 64, 254, 160, 3, 8, 224, 0, 15, 160, 3, 62, + 22, 99, 224, 0, 32, 133, 206, 112, 0, 79, 82, 0, 131, 120, 224, 0, 3, 15, 192, 5, 49, + 38, 32, 106, 112, 0, 34, 190, 208, 112, 0, 63, 230, 222, 6, 112, 0, 70, 23, 160, 112, + 0, 32, 148, 210, 112, 0, 65, 92, 0, 27, 138, 224, 0, 1, 240, 84, 15, 160, 6, 3, 15, + 234, 0, 43, 0, 168, 2, 0, 56, 2, 4, 200, 1, 49, 127, 30, 255, 200, 1, 8, 56, 2, 15, + 200, 1, 61, 0, 56, 2, 19, 60, 112, 0, 32, 14, 44, 112, 0, 25, 72, 56, 2, 15, 120, 3, + 49, 19, 65, 96, 0, 64, 213, 145, 0, 207, 232, 7, 8, 96, 0, 15, 0, 5, 62, 22, 99, 64, 1, + 121, 125, 23, 1, 207, 0, 0, 79, 152, 2, 8, 64, 1, 15, 174, 1, 14, 15, 16, 7, 8, 0, 144, + 2, 4, 104, 0, 34, 19, 27, 104, 0, 8, 144, 2, 15, 104, 0, 53, 0, 136, 2, 4, 104, 0, 32, + 114, 29, 104, 0, 25, 89, 136, 2, 15, 104, 0, 3, 15, 218, 0, 37, 0, 142, 5, 2, 240, 5, + 38, 16, 108, 112, 3, 32, 150, 173, 120, 0, 65, 104, 0, 186, 0, 112, 3, 15, 0, 3, 8, 0, + 58, 9, 31, 16, 28, 10, 30, 51, 40, 105, 115, 207, 99, 81, 101, 114, 101, 100, 41, 128, + 0, 38, 192, 107, 128, 0, 32, 43, 176, 128, 0, 65, 78, 0, 70, 164, 128, 3, 5, 32, 10, 1, + 173, 0, 0, 4, 0, 1, 58, 88, 15, 210, 6, 5, 15, 146, 10, 5, 2, 232, 0, 23, 0, 104, 0, + 64, 173, 241, 3, 207, 126, 32, 31, 174, 232, 3, 80, 0, 64, 2, 4, 144, 6, 32, 106, 244, + 120, 0, 25, 82, 64, 2, 10, 96, 4, 0, 224, 0, 0, 3, 0, 15, 228, 0, 31, 0, 54, 0, 4, 88, + 4, 4, 232, 3, 121, 13, 173, 13, 207, 0, 0, 72, 88, 4, 15, 232, 3, 45, 38, 160, 99, 96, + 0, 121, 190, 201, 16, 207, 0, 0, 67, 120, 3, 8, 96, 0, 15, 158, 2, 14, 15, 32, 8, 0, 0, + 48, 1, 4, 96, 0, 34, 166, 204, 96, 0, 8, 48, 1, 15, 96, 0, 45, 0, 104, 3, 4, 96, 0, 32, + 126, 253, 96, 0, 25, 77, 104, 3, 15, 96, 0, 3, 15, 202, 0, 27, 4, 136, 1, 4, 16, 5, 49, + 197, 54, 17, 248, 1, 8, 136, 1, 15, 16, 5, 65, 4, 112, 0, 49, 50, 198, 27, 216, 0, 8, + 168, 7, 8, 112, 0, 15, 206, 0, 14, 15, 232, 10, 8, 0, 160, 1, 4, 104, 0, 34, 237, 200, + 104, 0, 8, 160, 1, 15, 104, 0, 53, 0, 168, 1, 4, 104, 0, 32, 199, 202, 104, 0, 25, 87, + 168, 1, 15, 104, 0, 3, 15, 218, 0, 35, 0, 176, 1, 0, 8, 5, 4, 128, 5, 121, 72, 92, 44, + 207, 0, 0, 101, 8, 5, 15, 128, 5, 3, 0, 2, 13, 15, 8, 5, 6, 15, 86, 6, 3, 12, 5, 5, 7, + 88, 101, 16, 152, 197, 3, 67, 0, 0, 0, 216, 8, 0, 19, 182, 15, 4, 15, 104, 16, 5, 19, + 63, 176, 0, 32, 50, 246, 200, 2, 50, 12, 0, 16, 208, 15, 13, 104, 16, 4, 40, 0, 49, + 160, 98, 26, 40, 0, 19, 17, 40, 0, 12, 104, 16, 4, 40, 0, 49, 168, 132, 33, 40, 0, 19, + 18, 40, 0, 12, 104, 16, 1, 190, 18, 2, 163, 0, 9, 5, 0, 27, 240, 104, 16, 1, 157, 37, + 66, 0, 0, 0, 235, 176, 16, 48, 0, 217, 7, 48, 38, 19, 24, 8, 0, 96, 0, 0, 242, 180, + 171, 186, 26, 0, 16, 63, 5, 0, 0, 192, 4, 101, 16, 8, 0, 81, 25, 3, 48, 0, 32, 236, + 175, 32, 0, 145, 112, 0, 233, 129, 54, 3, 128, 255, 2, 144, 6, 2, 128, 139, 81, 14, 0, + 2, 4, 104, 254, 119, 53, 22, 0, 58, 6, 156, 18, 99, 167, 35, 225, 115, 116, 111, 114, + 101, 100, 0, 100, 101, 110, 121, 40, 49, 41, 18, 112, 37, 45, 112, 166, 194, 165, 45, + 114, 101, 97, 100, 32, 107, 67, 70, 80, 19, 0, 131, 115, 65, 110, 121, 65, 112, 112, + 108, 136, 104, 1, 192, 99, 38, 144, 234, 80, 100, 162, 137, 39, 160, 187, 0, 0, 32, 0, + 65, 210, 32, 102, 1, 164, 21, 150, 8, 9, 125, 71, 88, 8, 107, 0, 93, 220, 123, 0, 56, + 0, 82, 9, 171, 148, 0, 127, 56, 1, 195, 0, 120, 85, 162, 187, 0, 0, 35, 0, 23, 202, 56, + 136, 100, 242, 9, 13, 0, 34, 4, 13, 0, 4, 0, 105, 102, 110, 101, 116, 95, 97, 116, 116, + 97, 99, 104, 0, 101, 110, 48, 1, 1, 0, 112, 47, 83, 160, 153, 1, 0, 138, 64, 0, 166, + 47, 77, 166, 187, 0, 0, 8, 0, 34, 50, 40, 97, 83, 48, 225, 159, 0, 57, 32, 0, 230, 43, + 206, 184, 187, 0, 0, 42, 0, 171, 139, 132, 0, 2, 3, 248, 123, 0, 32, 132, 0, 82, 91, + 243, 1, 107, 80, 77, 77, 105, 110, 117, 116, 101, 115, 84, 111, 83, 108, 101, 101, 71, + 155, 1, 224, 0, 8, 72, 0, 64, 41, 80, 185, 187, 120, 119, 12, 72, 0, 31, 16, 72, 0, 0, + 49, 68, 105, 109, 168, 0, 98, 220, 80, 8, 0, 234, 2, 81, 0, 240, 3, 180, 34, 187, 189, + 0, 0, 114, 0, 21, 32, 130, 1, 128, 255, 2, 14, 34, 4, 38, 200, 49, 34, 4, 14, 40, 96, + 17, 15, 6, 0, 17, 16, 6, 0, 17, 17, 6, 0, 17, 18, 236, 128, 113, 121, 28, 0, 0, 34, 4, + 19, 12, 0, 17, 67, 204, 1, 17, 20, 12, 0, 32, 160, 134, 22, 129, 1, 235, 131, 3, 24, 0, + 50, 21, 0, 1, 48, 103, 12, 254, 128, 1, 126, 0, 0, 224, 7, 70, 8, 0, 57, 86, 144, 0, + 32, 24, 122, 144, 0, 65, 141, 0, 139, 147, 144, 0, 31, 17, 144, 0, 19, 47, 231, 41, + 144, 0, 1, 128, 34, 4, 21, 0, 8, 0, 2, 4, 204, 2, 98, 2, 4, 194, 2, 0, 224, 4, 140, 3, + 141, 132, 1, 174, 0, 63, 34, 4, 30, 162, 0, 5, 7, 118, 90, 2, 168, 0, 98, 148, 117, 0, + 0, 155, 3, 184, 0, 49, 134, 243, 3, 16, 113, 128, 208, 45, 50, 1, 128, 255, 1, 3, 151, + 20, 40, 0, 0, 6, 0, 1, 39, 0, 1, 56, 0, 83, 16, 25, 3, 0, 20, 56, 0, 64, 130, 156, 80, + 190, 24, 116, 34, 228, 125, 24, 3, 2, 82, 97, 0, 230, 0, 2, 158, 97, 143, 14, 0, 34, 4, + 15, 0, 58, 0, 17, 3, 54, 1, 134, 0, 6, 160, 3, 4, 136, 0, 32, 127, 165, 136, 0, 31, 83, + 160, 3, 0, 81, 11, 0, 2, 4, 128, 212, 1, 53, 19, 0, 32, 160, 3, 150, 98, 108, 117, 101, + 116, 111, 111, 116, 104, 157, 3, 0, 171, 37, 1, 146, 3, 211, 45, 109, 101, 116, 97, + 100, 97, 116, 97, 32, 47, 117, 115, 65, 105, 0, 248, 0, 0, 48, 1, 19, 134, 104, 2, 64, + 237, 201, 84, 194, 200, 98, 15, 48, 1, 15, 2, 224, 2, 19, 53, 168, 0, 79, 133, 89, 112, + 195, 40, 3, 5, 0, 218, 0, 15, 40, 3, 9, 38, 16, 221, 8, 4, 162, 32, 121, 119, 195, 0, + 0, 24, 0, 68, 120, 8, 4, 0, 100, 3, 2, 118, 3, 2, 14, 157, 0, 88, 3, 23, 80, 48, 0, 32, + 100, 126, 48, 0, 81, 18, 0, 54, 123, 132, 200, 100, 0, 108, 0, 2, 48, 0, 0, 10, 0, 0, + 16, 2, 70, 2, 0, 32, 224, 96, 0, 32, 241, 129, 48, 0, 66, 6, 0, 52, 134, 58, 123, 0, + 80, 0, 23, 16, 216, 104, 32, 65, 163, 32, 0, 15, 72, 182, 3, 66, 8, 0, 29, 0, 105, 109, + 16, 80, 168, 21, 65, 83, 116, 97, 116, 115, 158, 15, 72, 182, 3, 10, 64, 99, 32, 144, + 200, 88, 0, 23, 54, 152, 107, 4, 160, 104, 4, 12, 107, 0, 129, 1, 2, 100, 0, 5, 169, + 104, 5, 9, 0, 2, 200, 0, 23, 160, 168, 0, 32, 206, 206, 80, 0, 15, 24, 99, 25, 115, 2, + 0, 144, 225, 159, 0, 94, 240, 6, 64, 155, 93, 120, 195, 144, 23, 34, 87, 151, 48, 100, + 0, 104, 1, 0, 3, 0, 0, 16, 1, 8, 216, 1, 63, 242, 252, 202, 216, 1, 6, 0, 52, 0, 15, + 216, 1, 21, 57, 4, 230, 208, 216, 1, 0, 108, 0, 2, 210, 1, 2, 6, 0, 0, 120, 0, 8, 216, + 1, 32, 129, 235, 48, 0, 12, 216, 1, 3, 189, 0, 3, 168, 0, 23, 0, 216, 1, 32, 227, 238, + 48, 0, 79, 6, 0, 155, 133, 216, 1, 3, 32, 81, 245, 32, 0, 15, 216, 1, 3, 63, 10, 0, 30, + 216, 1, 26, 23, 128, 120, 0, 49, 184, 79, 209, 72, 1, 34, 113, 144, 72, 1, 1, 125, 0, + 3, 160, 0, 8, 0, 2, 32, 206, 109, 40, 0, 15, 0, 2, 15, 0, 140, 0, 5, 247, 1, 5, 9, 0, + 2, 80, 0, 8, 0, 2, 32, 181, 117, 80, 0, 15, 0, 2, 27, 38, 0, 242, 0, 2, 32, 120, 166, + 64, 0, 81, 6, 0, 196, 29, 133, 178, 0, 0, 8, 4, 83, 35, 208, 0, 0, 200, 208, 3, 32, + 146, 167, 32, 0, 240, 1, 61, 0, 93, 133, 213, 2, 128, 255, 2, 3, 2, 8, 0, 224, 172, 31, + 43, 0, 6, 140, 7, 0, 14, 5, 16, 27, 2, 154, 64, 76, 105, 110, 107, 14, 3, 160, 117, + 115, 32, 45, 32, 110, 111, 116, 32, 97, 109, 23, 16, 101, 46, 0, 0, 216, 1, 38, 112, + 218, 120, 0, 32, 100, 173, 88, 0, 68, 46, 0, 45, 97, 80, 110, 82, 34, 0, 107, 80, 77, + 242, 28, 0, 196, 139, 48, 97, 114, 116, 52, 21, 211, 105, 110, 103, 73, 110, 80, 114, + 111, 103, 114, 101, 115, 115, 80, 1, 0, 168, 3, 4, 192, 2, 32, 209, 178, 72, 0, 15, + 208, 1, 3, 63, 8, 0, 31, 208, 1, 26, 23, 96, 24, 3, 32, 227, 209, 88, 0, 63, 12, 0, 23, + 24, 3, 0, 8, 208, 1, 63, 255, 17, 210, 208, 1, 18, 0, 140, 0, 5, 199, 1, 5, 9, 0, 14, + 208, 1, 32, 167, 25, 80, 0, 15, 208, 1, 25, 85, 8, 0, 112, 231, 7, 8, 111, 176, 222, + 80, 47, 198, 0, 0, 161, 0, 215, 199, 9, 176, 6, 51, 9, 2, 8, 201, 1, 97, 0, 2, 4, 119, + 245, 4, 172, 1, 81, 22, 0, 34, 4, 22, 50, 6, 17, 22, 12, 0, 113, 44, 0, 34, 0, 34, 4, + 78, 202, 110, 0, 252, 110, 2, 56, 5, 0, 166, 9, 132, 101, 85, 83, 66, 72, 111, 115, + 116, 102, 141, 18, 115, 28, 8, 13, 22, 0, 32, 97, 108, 154, 127, 245, 4, 116, 101, 68, + 111, 119, 110, 115, 116, 114, 101, 97, 109, 66, 117, 115, 67, 117, 114, 114, 246, 110, + 4, 78, 0, 96, 85, 72, 67, 73, 80, 111, 58, 139, 0, 22, 2, 0, 0, 1, 2, 120, 6, 19, 198, + 167, 0, 79, 80, 14, 41, 202, 120, 6, 18, 3, 192, 10, 16, 148, 47, 5, 112, 0, 0, 0, 249, + 232, 54, 202, 160, 113, 8, 192, 10, 0, 156, 7, 17, 14, 214, 0, 17, 97, 238, 0, 51, 31, + 0, 39, 107, 115, 243, 1, 32, 80, 111, 108, 105, 99, 121, 0, 100, 105, 115, 107, 97, + 114, 98, 105, 144, 119, 15, 44, 7, 1, 2, 40, 7, 80, 100, 101, 118, 47, 114, 46, 0, 81, + 49, 115, 53, 115, 49, 136, 2, 2, 40, 8, 19, 237, 184, 0, 127, 135, 152, 230, 204, 0, 0, + 89, 40, 8, 6, 0, 224, 141, 79, 18, 0, 39, 0, 115, 0, 40, 2, 48, 1, 3, 248, 0, 4, 120, + 0, 32, 14, 164, 120, 0, 31, 131, 24, 8, 4, 17, 193, 248, 0, 53, 19, 0, 80, 24, 8, 159, + 99, 111, 114, 101, 97, 117, 100, 105, 111, 236, 0, 1, 6, 24, 8, 3, 83, 34, 115, 47, + 118, 97, 114, 47, 100, 98, 137, 32, 2, 53, 1, 4, 23, 205, 1, 250, 119, 82, 47, 85, 65, + 75, 76, 172, 47, 0, 158, 0, 0, 208, 1, 10, 16, 8, 79, 4, 70, 28, 206, 16, 8, 49, 79, + 163, 46, 34, 206, 16, 8, 25, 32, 238, 52, 48, 0, 12, 56, 6, 1, 163, 0, 1, 4, 0, 0, 144, + 4, 8, 16, 8, 32, 231, 55, 48, 0, 15, 16, 8, 7, 32, 81, 89, 32, 0, 15, 104, 4, 5, 31, + 32, 104, 4, 26, 8, 64, 4, 32, 22, 126, 88, 0, 15, 16, 6, 15, 63, 8, 0, 32, 80, 107, 6, + 8, 16, 6, 32, 206, 132, 80, 0, 15, 64, 4, 25, 2, 16, 8, 3, 7, 10, 48, 0, 227, 144, 64, + 0, 15, 16, 8, 1, 115, 8, 0, 32, 53, 8, 0, 175, 120, 5, 176, 90, 216, 196, 210, 0, 0, + 178, 0, 90, 98, 11, 104, 4, 24, 10, 104, 4, 49, 45, 46, 8, 104, 4, 0, 244, 2, 17, 17, + 224, 8, 17, 26, 12, 0, 130, 43, 0, 37, 0, 2, 4, 15, 14, 224, 8, 0, 6, 0, 32, 0, 1, 8, + 12, 53, 80, 0, 26, 88, 4, 5, 32, 4, 49, 48, 48, 49, 240, 48, 5, 26, 0, 0, 136, 4, 1, + 58, 4, 146, 101, 110, 117, 109, 101, 114, 97, 116, 101, 142, 128, 138, 67, 111, 109, + 112, 108, 101, 116, 101, 91, 120, 148, 86, 105, 114, 116, 117, 97, 108, 32, 66, 8, 11, + 116, 32, 65, 100, 97, 112, 116, 101, 232, 0, 0, 232, 6, 81, 78, 119, 1, 0, 88, 236, 4, + 208, 0, 0, 119, 147, 245, 210, 0, 0, 112, 0, 91, 99, 152, 232, 6, 1, 226, 116, 165, 98, + 0, 42, 42, 42, 42, 32, 91, 73, 79, 70, 0, 0, 133, 0, 213, 67, 111, 110, 116, 114, 111, + 108, 108, 101, 114, 85, 83, 66, 128, 123, 33, 93, 91, 45, 52, 80, 93, 32, 45, 45, 32, + 103, 198, 0, 147, 0, 16, 100, 13, 0, 208, 114, 101, 115, 117, 108, 116, 32, 61, 32, 84, + 82, 85, 69, 17, 0, 48, 48, 120, 100, 207, 177, 0, 92, 0, 17, 10, 136, 0, 83, 224, 48, + 9, 0, 89, 136, 0, 64, 7, 64, 246, 210, 210, 13, 33, 88, 51, 24, 139, 0, 80, 168, 1, 27, + 34, 4, 120, 32, 4, 184, 16, 19, 217, 8, 0, 19, 185, 144, 1, 15, 184, 16, 5, 19, 85, 88, + 0, 64, 48, 55, 243, 210, 232, 9, 18, 64, 56, 4, 13, 184, 16, 4, 40, 0, 64, 110, 183, 1, + 211, 40, 0, 19, 65, 40, 0, 12, 184, 16, 4, 40, 0, 49, 109, 12, 10, 40, 0, 19, 66, 40, + 0, 12, 184, 16, 4, 0, 15, 19, 191, 8, 0, 19, 132, 168, 0, 31, 96, 168, 0, 4, 18, 227, + 72, 0, 50, 0, 215, 100, 168, 0, 18, 80, 16, 0, 13, 168, 0, 4, 40, 0, 49, 239, 62, 255, + 208, 0, 18, 81, 16, 0, 5, 200, 33, 4, 40, 1, 19, 224, 160, 33, 19, 183, 128, 0, 19, + 118, 128, 0, 27, 208, 56, 17, 4, 8, 54, 4, 128, 6, 68, 135, 249, 137, 197, 8, 54, 4, + 88, 126, 15, 8, 54, 13, 53, 144, 24, 11, 64, 0, 64, 86, 143, 179, 197, 192, 1, 147, 53, + 96, 0, 0, 1, 0, 35, 1, 33, 48, 1, 4, 0, 43, 4, 40, 0, 49, 219, 127, 48, 184, 52, 3, + 248, 38, 5, 192, 54, 12, 80, 0, 79, 126, 51, 155, 201, 80, 0, 1, 12, 40, 0, 63, 105, + 46, 230, 40, 0, 18, 79, 118, 224, 95, 202, 80, 0, 5, 38, 112, 5, 200, 0, 160, 128, 103, + 29, 203, 0, 0, 52, 0, 241, 180, 61, 37, 53, 34, 4, 0, 248, 14, 240, 19, 4, 0, 18, 4, + 20, 0, 0, 0, 242, 4, 4, 0, 16, 0, 108, 111, 48, 0, 148, 113, 48, 250, 109, 122, 41, + 248, 30, 85, 104, 169, 127, 57, 62, 192, 115, 1, 12, 160, 0, 79, 26, 242, 36, 203, 120, + 0, 5, 38, 144, 83, 120, 0, 160, 253, 51, 37, 203, 0, 0, 137, 0, 102, 175, 64, 1, 32, + 34, 12, 136, 3, 0, 3, 0, 0, 191, 1, 17, 18, 168, 113, 2, 120, 0, 114, 0, 8, 0, 180, + 128, 252, 130, 202, 34, 3, 10, 0, 4, 152, 0, 16, 20, 53, 19, 1, 98, 4, 0, 224, 53, 0, + 168, 15, 16, 37, 76, 0, 65, 4, 38, 0, 11, 176, 0, 254, 1, 121, 133, 19, 120, 32, 67, + 203, 253, 243, 21, 218, 112, 197, 254, 208, 128, 192, 0, 50, 32, 40, 80, 138, 132, 7, + 144, 60, 70, 2, 2, 32, 6, 168, 0, 32, 27, 57, 168, 0, 15, 32, 1, 19, 240, 1, 246, 55, + 175, 207, 1, 83, 183, 154, 3, 133, 98, 222, 184, 245, 41, 65, 84, 0, 12, 32, 1, 32, + 107, 58, 80, 0, 14, 56, 2, 1, 40, 0, 7, 32, 1, 32, 94, 63, 40, 0, 31, 127, 32, 1, 17, + 63, 190, 0, 250, 32, 1, 9, 2, 52, 16, 17, 36, 26, 1, 4, 32, 1, 31, 1, 32, 1, 2, 15, + 192, 0, 5, 8, 16, 1, 32, 197, 70, 152, 0, 15, 16, 1, 19, 255, 1, 115, 126, 124, 121, + 85, 81, 70, 178, 97, 191, 122, 98, 177, 164, 32, 113, 16, 1, 1, 32, 169, 71, 80, 0, 15, + 16, 1, 15, 32, 36, 76, 40, 0, 15, 16, 1, 18, 63, 254, 0, 251, 48, 2, 9, 31, 64, 16, 1, + 22, 15, 192, 0, 1, 0, 224, 3, 68, 0, 191, 77, 2, 224, 3, 64, 222, 95, 48, 203, 72, 5, + 19, 49, 224, 3, 38, 161, 122, 8, 42, 0, 128, 40, 4, 40, 0, 32, 61, 145, 40, 0, 21, 16, + 40, 0, 80, 99, 82, 27, 2, 17, 132, 11, 3, 152, 42, 4, 40, 0, 117, 60, 56, 49, 203, 0, + 0, 36, 40, 0, 4, 216, 4, 4, 56, 0, 19, 50, 8, 0, 6, 160, 40, 10, 72, 4, 63, 79, 211, + 59, 80, 1, 7, 7, 112, 4, 47, 110, 220, 40, 0, 19, 63, 112, 46, 60, 40, 0, 10, 19, 224, + 184, 0, 79, 122, 69, 103, 205, 248, 3, 6, 7, 40, 0, 47, 235, 75, 40, 0, 11, 4, 8, 1, + 63, 63, 166, 143, 40, 0, 10, 4, 80, 0, 63, 32, 165, 144, 40, 0, 10, 4, 80, 0, 79, 65, + 230, 96, 206, 160, 0, 1, 0, 208, 1, 23, 112, 208, 1, 64, 153, 191, 107, 206, 208, 1, + 19, 51, 104, 1, 36, 212, 141, 208, 1, 10, 104, 1, 63, 152, 15, 117, 80, 0, 2, 1, 200, + 3, 7, 104, 1, 47, 20, 22, 40, 0, 19, 47, 98, 202, 40, 0, 19, 47, 86, 212, 40, 0, 19, + 63, 15, 139, 144, 40, 0, 18, 47, 187, 145, 40, 0, 19, 47, 22, 168, 40, 0, 5, 2, 248, + 40, 4, 104, 1, 113, 215, 171, 149, 206, 0, 0, 71, 248, 40, 19, 19, 248, 40, 119, 40, 0, + 34, 4, 40, 0, 11, 212, 25, 69, 109, 68, 78, 83, 54, 167, 21, 46, 126, 59, 240, 2, 46, + 100, 97, 105, 108, 121, 0, 100, 105, 99, 116, 105, 111, 110, 97, 114, 121, 104, 12, 85, + 4, 2, 176, 100, 7, 144, 5, 49, 196, 66, 215, 16, 40, 128, 64, 114, 5, 0, 19, 0, 34, 3, + 56, 6, 131, 40, 0, 0, 8, 192, 87, 112, 249, 246, 3, 3, 50, 3, 6, 240, 29, 15, 110, 0, + 11, 2, 46, 0, 0, 176, 26, 0, 72, 37, 4, 200, 0, 32, 86, 70, 104, 0, 17, 75, 232, 40, + 15, 104, 0, 1, 0, 210, 0, 31, 5, 210, 0, 26, 1, 103, 0, 1, 56, 31, 68, 32, 98, 7, 0, + 48, 8, 49, 112, 181, 251, 104, 0, 0, 216, 33, 15, 104, 0, 61, 0, 16, 35, 4, 104, 0, 34, + 146, 187, 104, 0, 0, 48, 29, 15, 104, 0, 61, 38, 32, 101, 208, 0, 32, 21, 192, 104, 0, + 65, 64, 0, 199, 254, 160, 1, 20, 2, 160, 1, 0, 216, 7, 0, 3, 0, 15, 150, 1, 21, 0, 40, + 1, 38, 160, 99, 88, 0, 49, 198, 92, 254, 248, 1, 0, 128, 29, 15, 192, 0, 1, 15, 98, 0, + 31, 2, 47, 0, 0, 104, 0, 0, 128, 29, 4, 40, 1, 34, 33, 132, 104, 0, 0, 128, 29, 15, + 104, 0, 58, 101, 16, 10, 0, 56, 63, 0, 200, 2, 64, 149, 188, 189, 207, 16, 64, 246, 5, + 156, 38, 0, 0, 58, 14, 40, 5, 136, 208, 54, 178, 169, 6, 122, 173, 231, 92, 51, 77, 78, + 10, 0, 0, 3, 10, 120, 4, 49, 59, 12, 32, 56, 12, 15, 64, 8, 2, 7, 120, 4, 47, 90, 100, + 40, 0, 19, 63, 255, 212, 183, 40, 0, 18, 63, 223, 68, 218, 40, 0, 18, 63, 53, 214, 222, + 40, 0, 18, 47, 241, 225, 40, 0, 19, 47, 51, 232, 40, 0, 7, 38, 128, 82, 240, 0, 161, + 156, 179, 224, 210, 0, 0, 57, 0, 59, 56, 74, 123, 17, 2, 125, 66, 1, 158, 14, 248, 3, + 37, 0, 32, 40, 110, 111, 32, 115, 99, 104, 101, 100, 117, 108, 101, 100, 32, 99, 217, + 16, 18, 32, 225, 23, 9, 0, 10, 23, 64, 136, 9, 64, 53, 104, 225, 210, 48, 28, 32, 79, + 57, 88, 0, 14, 144, 1, 63, 66, 27, 229, 160, 0, 6, 8, 224, 11, 32, 14, 69, 200, 12, 15, + 232, 8, 4, 7, 40, 0, 79, 128, 82, 7, 211, 168, 6, 1, 12, 88, 6, 63, 101, 44, 13, 40, 0, + 18, 47, 64, 92, 40, 0, 11, 4, 248, 2, 63, 240, 37, 20, 40, 0, 18, 47, 156, 43, 40, 0, + 11, 4, 224, 2, 47, 72, 183, 40, 0, 19, 63, 219, 34, 21, 40, 0, 18, 47, 123, 66, 40, 0, + 11, 4, 200, 0, 63, 223, 117, 22, 40, 0, 18, 63, 154, 228, 27, 40, 0, 18, 47, 72, 233, + 40, 0, 11, 4, 240, 0, 63, 23, 97, 28, 40, 0, 18, 63, 175, 1, 29, 40, 0, 10, 4, 200, 0, + 47, 172, 184, 40, 0, 7, 53, 32, 12, 11, 24, 5, 176, 177, 185, 38, 211, 0, 0, 90, 0, 13, + 179, 4, 248, 2, 18, 9, 192, 13, 113, 0, 4, 0, 208, 0, 192, 0, 80, 29, 2, 10, 3, 32, + 242, 4, 145, 15, 2, 52, 30, 51, 0, 8, 108, 239, 2, 49, 34, 4, 17, 240, 159, 240, 10, + 23, 0, 1, 0, 160, 28, 35, 169, 146, 51, 93, 88, 233, 169, 240, 87, 172, 165, 237, 112, + 0, 116, 105, 109, 101, 39, 22, 1, 44, 0, 4, 128, 2, 17, 94, 78, 0, 95, 0, 0, 242, 104, + 52, 160, 0, 6, 53, 96, 247, 10, 40, 0, 176, 125, 45, 53, 211, 0, 0, 59, 0, 82, 229, 3, + 160, 0, 21, 5, 160, 0, 1, 232, 13, 0, 245, 32, 6, 154, 0, 241, 2, 5, 0, 154, 211, 61, + 159, 183, 85, 188, 107, 112, 136, 252, 39, 61, 239, 144, 14, 67, 0, 126, 0, 6, 240, 15, + 19, 152, 240, 15, 1, 21, 0, 7, 4, 0, 32, 136, 15, 13, 14, 19, 0, 142, 1, 0, 168, 3, + 115, 8, 0, 192, 130, 9, 0, 90, 136, 0, 49, 95, 224, 250, 200, 3, 48, 30, 45, 143, 112, + 17, 1, 32, 0, 38, 121, 134, 32, 0, 160, 86, 60, 68, 211, 0, 0, 117, 0, 28, 107, 32, 0, + 2, 24, 18, 31, 103, 24, 18, 13, 32, 93, 91, 169, 185, 106, 105, 97, 108, 105, 122, 101, + 50, 18, 5, 168, 123, 2, 40, 18, 128, 97, 108, 108, 105, 110, 103, 32, 83, 135, 231, 6, + 87, 18, 35, 40, 41, 29, 18, 1, 24, 13, 70, 8, 0, 170, 132, 144, 0, 32, 239, 70, 144, 0, + 70, 153, 0, 181, 88, 144, 0, 31, 139, 144, 0, 15, 11, 98, 0, 9, 126, 0, 50, 115, 101, + 116, 212, 21, 0, 187, 25, 72, 101, 32, 40, 107, 240, 18, 38, 67, 73, 152, 0, 7, 38, 0, + 4, 251, 166, 167, 116, 117, 112, 80, 101, 110, 100, 105, 110, 103, 180, 0, 0, 126, 1, + 0, 72, 1, 23, 33, 184, 0, 32, 190, 80, 184, 0, 70, 189, 0, 170, 84, 184, 0, 31, 175, + 184, 0, 15, 10, 156, 0, 1, 183, 0, 31, 109, 145, 0, 2, 98, 32, 61, 32, 85, 110, 105, + 118, 1, 255, 0, 122, 101, 100, 44, 32, 32, 109, 80, 114, 101, 118, 105, 111, 117, 115, + 48, 0, 5, 147, 79, 110, 32, 76, 105, 110, 101, 44, 32, 250, 5, 2, 255, 0, 20, 61, 168, + 215, 1, 51, 1, 19, 32, 222, 0, 0, 221, 0, 0, 231, 28, 1, 32, 2, 23, 167, 216, 0, 32, + 202, 88, 216, 0, 70, 156, 0, 235, 86, 216, 0, 31, 142, 216, 0, 34, 4, 13, 2, 231, 115, + 101, 116, 80, 114, 111, 112, 101, 114, 116, 121, 32, 40, 39, 116, 1, 32, 39, 41, 255, + 0, 2, 166, 6, 1, 172, 0, 194, 78, 117, 109, 98, 101, 114, 32, 61, 32, 49, 32, 40, 145, + 1, 2, 74, 2, 4, 181, 0, 8, 147, 1, 0, 184, 0, 38, 64, 133, 72, 2, 64, 67, 139, 150, + 211, 192, 6, 32, 233, 92, 184, 0, 2, 104, 2, 38, 16, 186, 32, 0, 49, 47, 48, 151, 32, + 0, 50, 181, 179, 145, 32, 0, 71, 16, 8, 0, 128, 64, 0, 32, 6, 53, 32, 0, 65, 14, 0, + 104, 93, 64, 0, 114, 1, 2, 4, 188, 2, 0, 224, 72, 0, 23, 192, 40, 0, 160, 27, 174, 185, + 211, 0, 0, 148, 0, 121, 96, 40, 0, 2, 64, 3, 31, 134, 32, 1, 15, 1, 200, 0, 3, 119, + 153, 6, 192, 1, 1, 0, 2, 64, 98, 101, 102, 111, 85, 154, 48, 120, 105, 116, 15, 0, 4, + 55, 1, 6, 38, 0, 1, 60, 0, 4, 22, 22, 17, 40, 53, 1, 5, 132, 21, 32, 48, 120, 85, 22, + 11, 24, 1, 38, 83, 168, 216, 0, 32, 98, 212, 176, 0, 64, 86, 0, 34, 104, 248, 0, 2, + 176, 0, 97, 72, 0, 72, 67, 73, 82, 34, 143, 200, 119, 97, 115, 32, 115, 101, 110, 116, + 32, 98, 121, 32, 39, 3, 9, 229, 3, 47, 58, 58, 141, 0, 4, 15, 24, 3, 0, 32, 202, 234, + 112, 0, 25, 203, 24, 3, 31, 189, 32, 1, 15, 15, 24, 3, 25, 15, 27, 2, 1, 15, 32, 3, 17, + 15, 56, 0, 4, 7, 129, 2, 50, 32, 61, 32, 23, 1, 3, 113, 2, 0, 88, 1, 1, 38, 3, 2, 232, + 0, 8, 40, 3, 32, 131, 243, 232, 0, 25, 149, 40, 3, 31, 135, 232, 0, 34, 4, 241, 1, 15, + 40, 3, 32, 57, 52, 32, 40, 176, 0, 7, 33, 3, 0, 32, 3, 0, 176, 4, 19, 95, 24, 6, 121, + 242, 96, 201, 211, 0, 0, 214, 152, 1, 31, 200, 176, 0, 34, 15, 176, 4, 6, 9, 139, 0, + 15, 145, 1, 54, 3, 182, 1, 67, 80, 111, 115, 116, 157, 1, 1, 16, 3, 4, 20, 4, 0, 242, + 0, 0, 163, 1, 0, 240, 0, 0, 160, 1, 4, 240, 0, 32, 98, 177, 240, 0, 25, 167, 160, 1, + 31, 153, 240, 0, 34, 15, 160, 1, 40, 21, 53, 200, 4, 15, 191, 0, 5, 5, 178, 1, 0, 192, + 0, 8, 176, 1, 121, 191, 49, 202, 211, 0, 0, 232, 176, 1, 31, 218, 192, 0, 34, 15, 176, + 1, 6, 15, 90, 1, 12, 15, 194, 1, 54, 111, 68, 97, 101, 109, 111, 110, 3, 1, 6, 0, 2, 1, + 2, 56, 26, 8, 192, 1, 32, 136, 78, 0, 1, 15, 136, 6, 147, 23, 195, 32, 6, 32, 35, 127, + 184, 0, 70, 162, 0, 202, 100, 32, 6, 31, 148, 184, 1, 15, 6, 164, 1, 1, 222, 2, 4, 238, + 5, 1, 33, 6, 7, 129, 2, 7, 62, 7, 15, 216, 8, 19, 2, 124, 1, 9, 84, 0, 5, 115, 2, 1, + 217, 4, 4, 120, 2, 4, 64, 10, 32, 16, 139, 192, 0, 25, 211, 120, 2, 31, 197, 192, 0, + 15, 15, 192, 5, 118, 2, 241, 0, 3, 56, 8, 4, 71, 1, 0, 242, 0, 16, 10, 238, 0, 2, 200, + 5, 23, 164, 200, 5, 32, 22, 146, 240, 0, 70, 139, 0, 195, 85, 176, 1, 31, 125, 240, 0, + 34, 63, 83, 101, 116, 108, 3, 5, 36, 116, 111, 157, 9, 8, 208, 1, 4, 207, 50, 3, 184, + 168, 8, 38, 11, 2, 168, 0, 0, 16, 3, 4, 152, 1, 121, 51, 140, 203, 211, 0, 0, 143, 16, + 3, 31, 129, 168, 0, 34, 7, 79, 2, 15, 152, 9, 29, 51, 48, 32, 40, 200, 0, 5, 172, 0, 0, + 64, 2, 23, 172, 96, 12, 32, 127, 185, 168, 0, 70, 171, 0, 41, 109, 80, 1, 31, 157, 168, + 0, 15, 18, 73, 234, 10, 15, 96, 12, 20, 21, 109, 192, 30, 146, 70, 97, 109, 105, 108, + 121, 45, 62, 109, 184, 147, 122, 67, 108, 105, 101, 110, 116, 115, 28, 3, 2, 87, 31, 5, + 217, 30, 18, 80, 107, 177, 0, 216, 184, 6, 55, 9, 1, 112, 1, 38, 55, 50, 56, 9, 49, + 160, 252, 204, 64, 6, 32, 107, 135, 184, 30, 2, 56, 9, 15, 64, 6, 0, 2, 128, 0, 149, + 93, 91, 80, 114, 111, 99, 101, 115, 115, 152, 0, 5, 110, 0, 129, 83, 104, 111, 119, + 115, 85, 112, 65, 234, 21, 41, 87, 76, 209, 3, 7, 113, 9, 2, 72, 0, 22, 39, 228, 52, 6, + 21, 2, 144, 45, 45, 32, 48, 120, 55, 50, 49, 48, 59, 0, 32, 48, 120, 70, 32, 2, 10, 0, + 6, 118, 31, 18, 10, 48, 2, 23, 58, 192, 0, 151, 85, 66, 205, 211, 0, 0, 152, 0, 231, + 192, 0, 31, 138, 192, 0, 60, 15, 117, 1, 41, 0, 112, 1, 23, 61, 176, 0, 32, 78, 80, + 176, 0, 70, 161, 0, 172, 136, 112, 1, 31, 147, 176, 0, 17, 240, 104, 101, 116, 111, + 111, 116, 104, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 104, 111, 119, 115, 85, + 112, 65, 99, 116, 105, 111, 110, 87, 76, 93, 32, 45, 45, 32, 67, 111, 110, 110, 101, + 99, 116, 101, 100, 32, 116, 111, 32, 116, 104, 101, 32, 116, 114, 97, 110, 115, 112, + 111, 114, 116, 32, 115, 117, 99, 99, 101, 115, 115, 102, 117, 108, 108, 121, 32, 45, + 45, 32, 48, 120, 55, 50, 49, 48, 32, 45, 45, 32, 48, 120, 49, 48, 48, 48, 32, 45, 45, + 32, 48, 120, 100, 48, 48, 48, 32, 42, 42, 42, 42, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 118, 52, 36, + ]; + + let (_, chunkset) = ChunksetChunk::parse_chunkset(&test_chunk_chunkset).unwrap(); + assert_eq!(chunkset.chunk_tag, 0x600d); + assert_eq!(chunkset.chunk_sub_tag, 17); + assert_eq!(chunkset.chunk_data_size, 21703); + assert_eq!(chunkset.signature, 825521762); // "bv41" + assert_eq!(chunkset.uncompress_size, 63560); + assert_eq!(chunkset.block_size, 21687); + assert_eq!(chunkset.decompressed_data.len(), 63560); + assert_eq!(chunkset.footer, 607417954); // "bv4$" + } + + #[test] + fn test_chunkset_with_oversize() { + let test_data = [ + 13, 96, 0, 0, 17, 0, 0, 0, 22, 81, 0, 0, 0, 0, 0, 0, 98, 118, 52, 49, 128, 244, 0, 0, + 6, 81, 0, 0, 50, 1, 96, 0, 1, 0, 16, 16, 5, 0, 36, 0, 0, 15, 0, 19, 237, 8, 0, 33, 240, + 15, 26, 0, 19, 3, 15, 0, 178, 0, 2, 1, 4, 0, 192, 205, 76, 2, 156, 2, 18, 0, 161, 92, + 219, 220, 242, 0, 0, 12, 0, 19, 5, 16, 0, 65, 128, 195, 126, 42, 26, 0, 132, 4, 0, 2, + 0, 48, 138, 26, 0, 40, 0, 242, 48, 11, 44, 142, 243, 0, 0, 89, 0, 175, 47, 6, 0, 34, 1, + 34, 4, 0, 0, 77, 0, 47, 83, 121, 115, 116, 101, 109, 47, 76, 105, 98, 114, 97, 114, + 121, 47, 68, 114, 105, 118, 101, 114, 69, 120, 116, 101, 110, 115, 105, 111, 110, 115, + 47, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 27, 0, 80, 75, 105, 116, 45, 65, 16, + 0, 240, 3, 69, 116, 104, 101, 114, 110, 101, 116, 69, 49, 48, 48, 48, 46, 100, 101, + 120, 116, 116, 0, 0, 3, 0, 102, 4, 0, 2, 2, 0, 156, 120, 0, 211, 197, 123, 167, 243, 0, + 0, 48, 0, 240, 101, 8, 0, 30, 122, 0, 47, 34, 0, 89, 0, 6, 141, 85, 83, 66, 67, 72, 67, + 79, 77, 232, 0, 64, 48, 3, 206, 243, 232, 0, 27, 20, 232, 0, 12, 40, 0, 64, 86, 185, 7, + 244, 40, 0, 27, 21, 40, 0, 12, 16, 1, 119, 112, 74, 88, 244, 0, 0, 84, 16, 1, 31, 72, + 16, 1, 40, 4, 183, 0, 6, 11, 1, 12, 8, 1, 121, 61, 220, 106, 244, 0, 0, 49, 8, 1, 31, + 35, 8, 1, 10, 96, 83, 101, 114, 105, 97, 108, 84, 1, 0, 3, 0, 12, 232, 0, 49, 105, 183, + 136, 232, 0, 27, 22, 232, 0, 12, 40, 0, 49, 232, 71, 193, 40, 0, 27, 23, 40, 0, 12, 16, + 1, 119, 23, 134, 0, 245, 0, 0, 85, 16, 1, 31, 73, 16, 1, 43, 2, 191, 0, 5, 17, 1, 1, + 112, 0, 37, 26, 27, 24, 2, 179, 155, 113, 72, 245, 0, 0, 73, 0, 38, 109, 18, 22, 2, 48, + 61, 0, 75, 84, 2, 240, 9, 108, 32, 114, 101, 113, 117, 101, 115, 116, 32, 102, 97, 105, + 108, 101, 100, 58, 32, 40, 105, 111, 107, 105, 116, 141, 2, 240, 12, 109, 111, 110, 41, + 32, 110, 111, 116, 32, 114, 101, 97, 100, 121, 32, 40, 45, 53, 51, 54, 56, 55, 48, 49, + 56, 52, 41, 36, 1, 0, 4, 0, 0, 104, 0, 38, 64, 9, 104, 0, 32, 149, 181, 104, 0, 80, 6, + 0, 160, 134, 18, 31, 0, 118, 0, 4, 16, 2, 0, 16, 25, 32, 0, 164, 214, 61, 110, 245, 0, + 0, 79, 0, 158, 105, 136, 0, 241, 7, 67, 0, 69, 114, 114, 111, 114, 32, 68, 111, 109, + 97, 105, 110, 61, 78, 83, 80, 79, 83, 73, 88, 20, 0, 2, 19, 0, 242, 20, 32, 67, 111, + 100, 101, 61, 50, 32, 34, 78, 111, 32, 115, 117, 99, 104, 32, 102, 105, 108, 101, 32, + 111, 114, 32, 100, 105, 114, 101, 99, 116, 111, 114, 121, 34, 136, 0, 38, 192, 148, 8, + 3, 179, 69, 2, 114, 245, 0, 0, 97, 0, 23, 55, 7, 104, 0, 245, 16, 85, 0, 97, 117, 120, + 105, 108, 105, 97, 114, 121, 32, 107, 101, 120, 116, 32, 99, 111, 108, 108, 101, 99, + 116, 105, 111, 110, 32, 97, 116, 32, 150, 3, 2, 22, 1, 21, 67, 29, 0, 52, 115, 47, 65, + 56, 0, 2, 27, 0, 6, 177, 3, 49, 46, 107, 99, 229, 0, 3, 8, 1, 23, 224, 128, 0, 164, + 128, 14, 146, 245, 0, 0, 70, 0, 95, 57, 128, 0, 29, 58, 224, 1, 2, 79, 0, 8, 106, 0, + 66, 66, 111, 111, 116, 22, 0, 12, 101, 0, 12, 224, 0, 64, 38, 82, 147, 245, 190, 4, 6, + 224, 0, 129, 84, 0, 98, 111, 111, 116, 32, 107, 63, 0, 12, 221, 0, 11, 122, 4, 2, 100, + 0, 15, 122, 0, 17, 0, 120, 0, 38, 176, 4, 192, 1, 224, 138, 121, 113, 251, 0, 0, 185, + 0, 233, 8, 18, 0, 34, 4, 216, 4, 255, 4, 23, 0, 34, 4, 23, 0, 37, 0, 34, 4, 60, 0, 58, + 0, 34, 4, 118, 0, 37, 138, 0, 4, 255, 22, 0, 66, 48, 70, 54, 53, 49, 69, 49, 45, 69, + 65, 48, 65, 45, 69, 50, 49, 66, 45, 48, 54, 70, 50, 45, 69, 50, 68, 51, 66, 51, 54, 69, + 69, 53, 50, 49, 38, 1, 40, 15, 95, 0, 18, 3, 177, 1, 0, 216, 0, 8, 48, 2, 119, 87, 203, + 127, 251, 0, 0, 98, 48, 2, 49, 86, 0, 115, 53, 1, 15, 45, 2, 2, 15, 80, 1, 14, 2, 33, + 0, 2, 104, 1, 12, 204, 1, 0, 130, 0, 0, 128, 0, 8, 88, 1, 175, 164, 197, 68, 253, 0, 0, + 187, 0, 236, 13, 88, 1, 1, 127, 60, 0, 34, 4, 120, 0, 37, 146, 0, 4, 255, 22, 0, 52, + 70, 56, 65, 56, 66, 51, 56, 45, 69, 51, 53, 49, 45, 54, 54, 51, 56, 45, 48, 53, 53, 70, + 45, 55, 54, 56, 55, 52, 50, 53, 67, 56, 49, 52, 54, 88, 1, 16, 15, 180, 0, 7, 15, 97, + 0, 18, 0, 215, 0, 176, 0, 4, 0, 4, 2, 208, 134, 65, 6, 190, 4, 14, 0, 243, 0, 0, 0, 32, + 237, 181, 12, 1, 0, 8, 0, 252, 202, 62, 6, 15, 248, 0, 38, 64, 23, 80, 2, 164, 50, 242, + 247, 56, 1, 0, 71, 0, 52, 24, 16, 4, 37, 59, 0, 139, 3, 102, 83, 116, 97, 103, 101, + 100, 63, 1, 5, 25, 0, 7, 19, 0, 144, 83, 111, 102, 116, 82, 65, 73, 68, 46, 167, 1, 2, + 136, 3, 8, 96, 0, 119, 223, 3, 248, 56, 1, 0, 74, 96, 0, 31, 62, 96, 0, 27, 179, 72, + 105, 103, 104, 80, 111, 105, 110, 116, 82, 82, 99, 0, 1, 217, 0, 1, 248, 4, 7, 104, 0, + 32, 80, 13, 104, 0, 23, 72, 104, 0, 31, 60, 104, 0, 27, 146, 86, 77, 119, 97, 114, 101, + 71, 102, 120, 102, 0, 12, 96, 0, 32, 56, 23, 96, 0, 23, 75, 96, 0, 31, 63, 96, 0, 27, + 5, 200, 0, 50, 73, 79, 80, 99, 0, 0, 199, 0, 1, 48, 1, 38, 80, 71, 200, 0, 179, 12, + 109, 6, 57, 1, 0, 45, 0, 58, 57, 21, 144, 1, 241, 18, 33, 0, 75, 101, 120, 116, 65, + 117, 100, 105, 116, 76, 111, 97, 100, 83, 116, 97, 116, 117, 115, 40, 114, 97, 119, 86, + 97, 108, 117, 101, 58, 32, 51, 12, 6, 0, 72, 0, 38, 64, 24, 72, 0, 224, 50, 8, 7, 57, + 1, 0, 81, 0, 160, 124, 18, 0, 34, 2, 40, 4, 83, 29, 0, 34, 4, 29, 140, 8, 161, 115, + 111, 102, 116, 114, 97, 105, 100, 46, 100, 3, 9, 20, 46, 197, 1, 6, 211, 0, 15, 226, 1, + 7, 0, 182, 0, 3, 232, 1, 7, 112, 0, 32, 160, 63, 112, 0, 23, 91, 112, 0, 113, 36, 0, + 34, 4, 36, 0, 37, 112, 0, 80, 104, 105, 103, 104, 112, 197, 1, 81, 45, 116, 101, 99, + 104, 255, 0, 21, 46, 17, 1, 47, 82, 82, 119, 0, 2, 7, 32, 0, 1, 49, 0, 1, 119, 0, 13, + 120, 0, 32, 198, 107, 120, 0, 23, 79, 120, 0, 83, 26, 0, 34, 4, 26, 108, 8, 32, 118, + 109, 213, 1, 1, 63, 0, 21, 46, 225, 1, 15, 110, 0, 2, 5, 30, 0, 1, 45, 0, 14, 224, 0, + 32, 72, 150, 104, 0, 23, 93, 104, 0, 0, 114, 5, 49, 37, 0, 38, 104, 0, 15, 224, 0, 10, + 63, 73, 79, 80, 115, 0, 2, 5, 225, 0, 8, 18, 2, 12, 224, 0, 119, 3, 28, 10, 57, 1, 0, + 95, 120, 0, 2, 240, 5, 17, 54, 120, 0, 8, 224, 0, 102, 118, 109, 104, 103, 102, 115, + 106, 0, 0, 185, 10, 49, 105, 99, 97, 96, 7, 115, 83, 117, 112, 112, 111, 114, 116, 230, + 0, 114, 32, 84, 111, 111, 108, 115, 47, 49, 0, 3, 240, 0, 12, 72, 9, 155, 163, 37, 227, + 57, 1, 0, 12, 0, 24, 72, 9, 0, 40, 0, 53, 112, 191, 77, 144, 11, 49, 153, 68, 245, 40, + 0, 19, 25, 40, 0, 49, 212, 141, 62, 130, 11, 0, 40, 0, 8, 184, 11, 64, 214, 165, 31, + 58, 80, 0, 19, 26, 40, 0, 4, 184, 11, 12, 40, 0, 49, 42, 122, 240, 40, 0, 31, 27, 40, + 0, 12, 64, 3, 78, 12, 59, 80, 0, 27, 28, 40, 0, 0, 64, 1, 8, 8, 12, 119, 123, 127, 98, + 60, 1, 0, 71, 232, 9, 15, 224, 4, 43, 12, 176, 0, 64, 224, 208, 71, 61, 136, 0, 27, 29, + 136, 0, 12, 40, 0, 49, 144, 117, 93, 40, 0, 31, 30, 40, 0, 12, 64, 233, 101, 43, 62, + 80, 0, 31, 31, 40, 0, 12, 49, 4, 74, 66, 40, 0, 33, 96, 6, 23, 3, 15, 8, 13, 6, 64, + 223, 68, 163, 63, 128, 5, 6, 8, 13, 15, 128, 5, 51, 12, 224, 0, 64, 5, 225, 213, 63, + 184, 0, 27, 97, 144, 0, 12, 40, 0, 49, 196, 215, 233, 40, 0, 31, 98, 40, 0, 12, 64, + 185, 107, 49, 64, 80, 0, 31, 99, 40, 0, 12, 49, 184, 73, 72, 40, 0, 27, 100, 40, 0, 12, + 8, 2, 119, 57, 135, 126, 64, 1, 0, 72, 8, 2, 15, 32, 6, 43, 12, 216, 0, 64, 225, 255, + 114, 65, 176, 0, 27, 101, 136, 0, 12, 40, 0, 49, 253, 74, 138, 40, 0, 31, 102, 40, 0, + 12, 49, 195, 120, 244, 40, 0, 31, 103, 40, 0, 12, 64, 18, 77, 15, 66, 120, 0, 27, 104, + 40, 0, 12, 0, 1, 119, 159, 39, 18, 67, 1, 0, 75, 0, 1, 15, 192, 6, 55, 38, 96, 7, 8, 6, + 163, 140, 51, 51, 67, 1, 0, 6, 0, 40, 48, 128, 12, 71, 0, 2, 0, 208, 32, 0, 49, 230, + 22, 52, 32, 0, 34, 39, 50, 32, 0, 19, 1, 1, 16, 33, 128, 1, 15, 0, 33, 0, 81, 6, 0, 50, + 0, 0, 224, 7, 0, 49, 0, 112, 1, 16, 16, 1, 84, 4, 0, 4, 0, 0, 224, 8, 83, 160, 103, + 218, 18, 137, 18, 0, 192, 149, 70, 123, 183, 0, 0, 8, 0, 10, 178, 217, 18, 19, 0, 132, + 4, 0, 2, 2, 160, 225, 0, 0, 32, 0, 64, 141, 158, 115, 21, 0, 9, 64, 102, 93, 0, 0, 99, + 0, 0, 32, 0, 23, 192, 32, 0, 146, 67, 56, 117, 21, 1, 0, 14, 0, 253, 32, 0, 50, 1, 0, + 4, 123, 16, 12, 104, 0, 49, 4, 237, 121, 72, 0, 5, 104, 0, 86, 16, 2, 2, 112, 231, 104, + 0, 161, 89, 53, 99, 67, 1, 0, 28, 0, 59, 155, 104, 0, 242, 4, 2, 0, 8, 60, 63, 120, + 109, 108, 32, 118, 101, 0, 8, 82, 97, 100, 32, 77, 97, 171, 12, 0, 128, 0, 38, 128, + 220, 56, 0, 49, 137, 166, 101, 56, 0, 32, 137, 61, 56, 0, 2, 170, 16, 129, 14, 0, 47, + 99, 111, 114, 101, 115, 6, 0, 32, 46, 49, 247, 0, 0, 144, 6, 39, 2, 192, 56, 0, 34, + 184, 187, 56, 0, 47, 9, 62, 56, 0, 15, 38, 160, 227, 56, 0, 32, 201, 196, 56, 0, 64, + 18, 0, 106, 139, 56, 0, 16, 0, 27, 1, 0, 95, 0, 5, 3, 0, 19, 2, 144, 1, 19, 100, 64, + 10, 3, 15, 0, 5, 160, 17, 97, 215, 95, 215, 67, 1, 0, 60, 0, 112, 0, 68, 4, 0, 0, 34, + 5, 92, 8, 2, 148, 6, 0, 38, 11, 17, 83, 128, 7, 175, 109, 0, 56, 0, 34, 4, 165, 0, 127, + 3, 196, 11, 3, 15, 13, 11, 42, 15, 71, 14, 6, 6, 209, 2, 2, 248, 11, 8, 96, 13, 15, 68, + 14, 10, 60, 10, 9, 9, 145, 0, 2, 1, 18, 7, 6, 9, 15, 195, 17, 0, 16, 46, 99, 7, 129, + 101, 85, 115, 101, 114, 69, 67, 77, 250, 15, 15, 73, 0, 49, 79, 68, 97, 116, 97, 77, 0, + 32, 5, 140, 0, 50, 72, 73, 68, 189, 0, 31, 115, 70, 0, 32, 2, 58, 0, 5, 248, 18, 118, + 85, 83, 66, 83, 76, 67, 79, 221, 0, 4, 59, 19, 1, 110, 0, 12, 52, 1, 7, 46, 1, 1, 32, + 0, 0, 184, 10, 177, 69, 120, 99, 108, 117, 100, 101, 76, 105, 115, 116, 106, 8, 15, 34, + 1, 36, 17, 45, 81, 0, 73, 85, 83, 66, 80, 143, 0, 11, 129, 0, 2, 190, 0, 7, 135, 0, 15, + 181, 1, 11, 3, 213, 19, 79, 65, 83, 73, 88, 43, 1, 50, 1, 202, 19, 15, 74, 0, 47, 143, + 49, 54, 88, 53, 48, 80, 67, 73, 74, 0, 47, 0, 191, 1, 1, 86, 19, 15, 75, 0, 47, 14, 2, + 21, 15, 202, 1, 45, 50, 70, 84, 68, 227, 0, 1, 98, 4, 4, 8, 6, 16, 168, 165, 14, 64, 0, + 0, 0, 67, 21, 0, 66, 0, 0, 0, 217, 7, 0, 43, 0, 152, 24, 22, 147, 4, 0, 10, 0, 208, 61, + 0, 0, 178, 168, 4, 241, 12, 99, 78, 190, 223, 0, 0, 22, 0, 194, 45, 0, 0, 123, 13, 55, + 117, 241, 144, 62, 33, 186, 19, 4, 71, 196, 27, 135, 75, 0, 147, 4, 0, 10, 2, 112, 118, + 0, 0, 101, 48, 0, 241, 18, 236, 118, 241, 52, 1, 0, 161, 0, 147, 55, 0, 0, 192, 236, + 183, 231, 68, 105, 57, 201, 185, 211, 112, 154, 25, 12, 230, 187, 35, 0, 34, 2, 66, 40, + 0, 0, 6, 0, 255, 28, 125, 0, 40, 10, 32, 32, 32, 32, 34, 83, 101, 116, 117, 112, 58, + 47, 78, 101, 116, 119, 111, 114, 107, 47, 83, 101, 114, 118, 105, 99, 101, 47, 91, 94, + 47, 93, 43, 47, 80, 80, 80, 34, 44, 40, 0, 16, 95, 73, 80, 83, 101, 99, 42, 0, 18, 81, + 86, 80, 78, 34, 10, 220, 13, 0, 2, 1, 0, 192, 0, 38, 48, 116, 192, 0, 175, 143, 37, + 244, 52, 1, 0, 73, 0, 255, 47, 192, 0, 2, 1, 72, 6, 17, 43, 36, 12, 2, 209, 22, 2, 136, + 5, 146, 46, 99, 111, 110, 102, 105, 103, 46, 110, 196, 0, 176, 95, 99, 104, 97, 110, + 103, 101, 46, 100, 110, 115, 100, 0, 0, 4, 0, 0, 104, 0, 23, 128, 104, 0, 32, 250, 47, + 104, 0, 79, 46, 0, 228, 51, 104, 0, 7, 35, 16, 0, 80, 0, 18, 32, 80, 0, 19, 100, 72, 0, + 8, 176, 0, 32, 118, 56, 72, 0, 31, 69, 176, 0, 10, 31, 39, 176, 0, 20, 15, 168, 0, 1, + 32, 100, 58, 96, 0, 15, 168, 0, 47, 32, 1, 64, 72, 0, 15, 88, 1, 79, 32, 124, 65, 104, + 0, 15, 176, 0, 47, 32, 230, 69, 72, 0, 15, 88, 1, 71, 32, 65, 71, 96, 0, 15, 168, 0, + 47, 32, 211, 75, 72, 0, 15, 88, 1, 79, 32, 61, 77, 104, 0, 15, 176, 0, 47, 32, 247, 80, + 72, 0, 15, 88, 1, 71, 32, 98, 82, 96, 0, 15, 168, 0, 47, 32, 248, 85, 72, 0, 15, 168, + 0, 71, 32, 95, 87, 96, 0, 15, 168, 0, 31, 0, 248, 12, 81, 80, 188, 15, 7, 149, 72, 5, + 81, 0, 0, 188, 23, 3, 168, 12, 16, 83, 61, 10, 112, 0, 0, 128, 219, 35, 14, 7, 200, 3, + 0, 40, 0, 23, 208, 40, 0, 49, 61, 37, 14, 40, 0, 19, 84, 40, 0, 38, 63, 135, 40, 0, 38, + 48, 193, 80, 0, 49, 211, 199, 21, 40, 0, 19, 85, 40, 0, 34, 233, 112, 40, 0, 0, 24, 6, + 83, 0, 63, 0, 0, 234, 0, 12, 49, 235, 157, 212, 40, 11, 243, 8, 214, 50, 0, 0, 248, + 224, 21, 103, 168, 217, 53, 171, 136, 221, 180, 79, 198, 217, 9, 148, 35, 1, 33, 158, + 0, 0, 240, 17, 10, 56, 0, 63, 57, 224, 233, 56, 0, 22, 38, 192, 62, 112, 0, 49, 68, + 172, 253, 56, 0, 47, 132, 49, 112, 0, 27, 64, 55, 1, 226, 68, 64, 12, 15, 168, 0, 17, + 8, 112, 0, 49, 253, 23, 250, 56, 0, 15, 112, 0, 29, 79, 237, 67, 23, 69, 112, 0, 20, + 99, 2, 224, 246, 0, 0, 25, 42, 1, 243, 14, 4, 122, 212, 69, 1, 0, 136, 0, 108, 183, 0, + 0, 179, 121, 27, 112, 86, 226, 56, 167, 180, 127, 38, 211, 24, 12, 62, 152, 31, 56, 7, + 134, 38, 0, 66, 4, 38, 0, 62, 0, 126, 9, 2, 126, 6, 240, 19, 115, 116, 97, 116, 115, + 46, 100, 97, 105, 108, 121, 46, 50, 54, 56, 52, 51, 53, 52, 53, 54, 0, 83, 117, 110, + 100, 97, 121, 44, 32, 74, 97, 110, 117, 28, 26, 128, 49, 54, 44, 32, 50, 48, 50, 50, + 21, 26, 241, 18, 49, 50, 58, 49, 53, 58, 48, 48, 32, 65, 77, 32, 80, 97, 99, 105, 102, + 105, 99, 32, 83, 116, 97, 110, 100, 97, 114, 100, 32, 84, 105, 109, 101, 168, 13, 98, + 128, 124, 74, 19, 243, 3, 160, 0, 64, 222, 186, 218, 69, 208, 13, 80, 149, 217, 72, 19, + 42, 167, 12, 4, 184, 0, 0, 64, 7, 52, 245, 0, 0, 40, 0, 174, 171, 19, 225, 69, 1, 0, + 86, 0, 78, 99, 200, 0, 64, 28, 0, 34, 1, 250, 7, 24, 56, 194, 0, 48, 111, 102, 116, 76, + 20, 240, 21, 117, 112, 100, 97, 116, 101, 100, 46, 108, 111, 103, 115, 45, 99, 108, + 101, 97, 110, 117, 112, 32, 40, 48, 120, 55, 102, 100, 56, 57, 55, 50, 48, 99, 50, 98, + 48, 181, 7, 0, 72, 7, 38, 80, 244, 112, 0, 174, 126, 184, 233, 69, 1, 0, 67, 0, 234, + 91, 112, 0, 19, 27, 248, 13, 2, 44, 21, 2, 176, 7, 1, 6, 0, 246, 6, 115, 115, 100, 98, + 103, 114, 101, 102, 114, 101, 115, 104, 46, 97, 99, 116, 105, 118, 105, 116, 121, 208, + 0, 23, 192, 96, 0, 175, 143, 181, 234, 69, 1, 0, 84, 0, 91, 92, 96, 0, 3, 0, 208, 0, 2, + 52, 20, 1, 90, 0, 2, 231, 30, 15, 96, 0, 2, 8, 206, 0, 49, 102, 98, 97, 206, 0, 1, 32, + 3, 9, 8, 2, 32, 104, 187, 112, 0, 31, 131, 8, 2, 10, 119, 34, 0, 66, 4, 34, 0, 61, 118, + 0, 213, 98, 115, 100, 46, 100, 105, 114, 104, 101, 108, 112, 101, 114, 4, 2, 31, 55, 4, + 2, 10, 63, 51, 58, 51, 3, 2, 11, 1, 17, 1, 12, 8, 2, 63, 201, 210, 237, 8, 2, 18, 49, + 237, 41, 240, 56, 1, 15, 8, 2, 9, 15, 56, 1, 45, 8, 8, 2, 127, 17, 205, 247, 69, 1, 0, + 68, 8, 2, 10, 2, 84, 22, 1, 162, 1, 5, 168, 1, 0, 60, 3, 106, 105, 115, 116, 105, 99, + 115, 9, 2, 0, 104, 2, 8, 152, 1, 127, 129, 230, 248, 69, 1, 0, 134, 152, 1, 10, 119, + 35, 0, 66, 4, 35, 0, 63, 102, 0, 229, 99, 115, 114, 117, 116, 105, 108, 46, 114, 101, + 112, 111, 114, 116, 153, 1, 121, 56, 0, 84, 104, 117, 114, 115, 159, 3, 38, 50, 48, + 159, 3, 79, 51, 58, 50, 48, 158, 3, 10, 2, 56, 2, 8, 168, 2, 127, 53, 60, 252, 69, 1, + 0, 85, 168, 2, 10, 23, 55, 154, 0, 15, 0, 1, 8, 5, 169, 2, 98, 53, 53, 49, 52, 56, 56, + 169, 2, 12, 8, 2, 63, 203, 23, 255, 8, 2, 18, 64, 200, 231, 0, 70, 152, 0, 15, 8, 2, 9, + 15, 152, 0, 43, 10, 64, 3, 127, 147, 215, 5, 70, 1, 0, 129, 168, 1, 10, 89, 30, 0, 66, + 4, 30, 168, 1, 149, 110, 101, 119, 115, 121, 115, 108, 111, 103, 163, 1, 121, 57, 0, + 83, 97, 116, 117, 114, 163, 1, 38, 49, 53, 163, 1, 49, 56, 58, 51, 163, 1, 31, 80, 65, + 5, 5, 0, 61, 3, 15, 176, 4, 0, 127, 191, 1, 12, 70, 1, 0, 56, 168, 2, 10, 23, 26, 16, + 1, 253, 0, 112, 101, 114, 105, 111, 100, 105, 99, 45, 119, 101, 101, 107, 108, 121, + 248, 1, 32, 231, 76, 80, 0, 31, 73, 248, 1, 10, 8, 176, 12, 11, 80, 0, 6, 236, 1, 82, + 52, 49, 53, 99, 52, 236, 1, 0, 186, 0, 12, 240, 1, 79, 253, 119, 14, 70, 0, 6, 17, 49, + 195, 18, 18, 144, 0, 15, 240, 1, 9, 15, 144, 0, 35, 10, 240, 3, 127, 183, 125, 20, 70, + 1, 0, 64, 72, 1, 10, 2, 148, 27, 1, 234, 2, 1, 138, 27, 81, 119, 97, 114, 101, 85, 104, + 6, 36, 46, 65, 245, 5, 0, 232, 3, 23, 192, 88, 0, 32, 221, 190, 88, 0, 31, 81, 80, 1, + 10, 31, 51, 88, 0, 15, 8, 88, 1, 63, 52, 49, 101, 88, 1, 7, 63, 94, 74, 22, 88, 1, 2, + 4, 184, 15, 16, 8, 166, 21, 15, 184, 15, 0, 30, 248, 184, 15, 9, 8, 3, 127, 153, 251, + 23, 70, 1, 0, 126, 8, 3, 10, 89, 29, 0, 66, 4, 29, 72, 6, 42, 103, 107, 170, 4, 47, 54, + 48, 67, 6, 12, 47, 53, 50, 168, 4, 16, 8, 32, 8, 49, 173, 89, 25, 96, 1, 15, 32, 2, 9, + 15, 96, 1, 43, 10, 40, 2, 79, 123, 115, 27, 70, 32, 8, 25, 242, 3, 115, 105, 114, 105, + 46, 109, 111, 114, 112, 104, 117, 110, 97, 115, 115, 101, 116, 115, 154, 8, 32, 114, + 100, 22, 3, 2, 208, 3, 8, 48, 2, 32, 245, 191, 96, 0, 15, 32, 8, 23, 15, 96, 0, 7, 6, + 51, 2, 83, 55, 49, 48, 52, 57, 51, 2, 12, 136, 3, 63, 186, 49, 32, 48, 2, 2, 0, 200, 2, + 8, 104, 1, 49, 63, 33, 35, 152, 0, 15, 104, 1, 9, 8, 128, 7, 15, 152, 0, 31, 10, 104, + 1, 127, 214, 22, 38, 70, 1, 0, 59, 144, 3, 10, 23, 29, 112, 0, 241, 3, 110, 97, 110, + 100, 46, 97, 115, 112, 99, 97, 114, 114, 121, 95, 98, 111, 111, 116, 95, 1, 13, 96, 1, + 32, 237, 96, 88, 0, 31, 76, 96, 1, 10, 31, 46, 88, 0, 10, 5, 88, 1, 111, 55, 51, 49, + 49, 53, 48, 88, 1, 4, 63, 253, 106, 42, 88, 1, 6, 8, 88, 3, 32, 27, 244, 40, 0, 31, + 132, 88, 3, 10, 2, 160, 9, 8, 168, 11, 48, 108, 111, 103, 15, 30, 100, 108, 111, 97, + 100, 115, 100, 7, 8, 106, 54, 49, 0, 84, 117, 101, 6, 8, 38, 49, 56, 99, 6, 19, 50, 6, + 8, 15, 99, 6, 10, 0, 48, 1, 8, 248, 1, 49, 222, 252, 44, 48, 1, 15, 248, 1, 9, 15, 48, + 1, 35, 10, 32, 13, 64, 92, 158, 46, 70, 232, 12, 15, 32, 13, 16, 9, 40, 2, 127, 209, + 45, 50, 70, 1, 0, 69, 40, 2, 10, 8, 176, 18, 97, 109, 111, 98, 105, 108, 101, 138, 3, + 178, 100, 46, 109, 101, 116, 97, 100, 97, 116, 97, 45, 148, 3, 0, 49, 2, 0, 0, 1, 8, + 144, 3, 64, 88, 114, 50, 70, 128, 12, 15, 176, 11, 9, 8, 128, 12, 15, 96, 0, 9, 5, 58, + 2, 84, 53, 54, 49, 56, 48, 128, 12, 10, 24, 13, 63, 113, 101, 51, 56, 2, 6, 8, 152, 1, + 49, 195, 88, 53, 152, 0, 15, 152, 1, 9, 15, 152, 0, 43, 10, 8, 9, 79, 17, 69, 56, 70, + 80, 14, 13, 89, 37, 0, 66, 4, 37, 8, 9, 49, 101, 109, 111, 151, 3, 102, 108, 109, 97, + 110, 97, 103, 75, 12, 47, 54, 50, 15, 9, 0, 38, 50, 50, 172, 2, 63, 51, 58, 50, 77, 12, + 11, 0, 168, 1, 8, 8, 2, 127, 184, 11, 58, 70, 1, 0, 78, 8, 2, 10, 30, 48, 16, 1, 0, + 183, 7, 1, 123, 33, 242, 0, 100, 46, 115, 112, 108, 117, 110, 107, 108, 111, 103, 103, + 105, 110, 103, 254, 14, 15, 16, 2, 0, 32, 150, 245, 104, 0, 31, 95, 64, 4, 10, 31, 65, + 104, 0, 29, 6, 25, 2, 80, 52, 49, 100, 99, 54, 83, 4, 12, 168, 5, 63, 97, 131, 60, 24, + 2, 18, 49, 85, 31, 62, 160, 0, 15, 24, 2, 9, 15, 160, 0, 51, 11, 176, 5, 47, 175, 64, + 24, 7, 26, 3, 40, 3, 7, 128, 1, 128, 68, 67, 82, 84, 46, 79, 79, 66, 134, 3, 2, 120, 1, + 23, 144, 224, 1, 49, 215, 51, 65, 96, 0, 47, 218, 97, 56, 15, 3, 0, 72, 23, 8, 152, 15, + 15, 96, 0, 17, 8, 64, 2, 49, 24, 203, 66, 96, 0, 15, 248, 15, 21, 14, 96, 0, 31, 85, + 192, 0, 10, 49, 241, 18, 67, 96, 0, 15, 192, 0, 39, 14, 96, 0, 8, 192, 0, 64, 109, 199, + 69, 70, 56, 33, 15, 192, 0, 9, 31, 42, 32, 1, 10, 9, 0, 3, 1, 128, 1, 8, 8, 5, 127, 11, + 15, 70, 70, 1, 0, 89, 248, 2, 10, 31, 59, 96, 0, 23, 5, 242, 2, 96, 55, 50, 49, 50, 49, + 49, 242, 2, 2, 1, 0, 12, 24, 20, 32, 234, 72, 120, 0, 15, 112, 19, 17, 10, 72, 5, 63, + 143, 33, 71, 48, 3, 18, 49, 107, 179, 72, 216, 0, 15, 48, 3, 9, 15, 216, 0, 52, 9, 48, + 3, 127, 202, 100, 75, 70, 1, 0, 87, 176, 4, 10, 31, 57, 120, 0, 23, 242, 0, 46, 114, + 111, 108, 108, 105, 100, 101, 110, 116, 105, 102, 105, 101, 114, 64, 3, 8, 192, 1, 32, + 211, 169, 112, 0, 31, 104, 192, 1, 10, 31, 74, 112, 0, 38, 5, 207, 1, 80, 53, 55, 49, + 49, 56, 218, 6, 12, 192, 4, 63, 42, 176, 76, 144, 1, 18, 49, 27, 228, 77, 168, 0, 15, + 144, 1, 9, 15, 168, 0, 59, 10, 200, 4, 64, 233, 22, 81, 70, 136, 37, 15, 72, 3, 9, 23, + 44, 128, 0, 130, 116, 105, 109, 101, 122, 111, 110, 101, 66, 8, 129, 115, 46, 108, 111, + 99, 97, 108, 45, 96, 8, 96, 45, 99, 104, 101, 99, 107, 213, 2, 2, 216, 2, 9, 144, 1, + 32, 35, 95, 104, 0, 31, 91, 144, 1, 10, 8, 146, 19, 15, 104, 0, 14, 5, 131, 1, 0, 82, + 3, 20, 99, 239, 11, 13, 120, 21, 63, 131, 72, 83, 136, 1, 18, 49, 234, 240, 87, 160, 0, + 15, 136, 1, 9, 15, 160, 0, 52, 69, 0, 105, 25, 7, 128, 21, 49, 175, 206, 90, 240, 15, + 242, 0, 136, 44, 6, 0, 66, 4, 32, 4, 0, 0, 23, 0, 0, 8, 140, 69, 1, 18, 0, 246, 35, 87, + 32, 4, 23, 0, 16, 124, 0, 54, 120, 112, 99, 109, 19, 4, 253, 48, 117, 112, 114, 111, + 99, 101, 115, 115, 57, 0, 11, 48, 8, 32, 225, 216, 104, 0, 31, 40, 128, 3, 10, 189, 10, + 0, 60, 85, 110, 107, 110, 111, 119, 110, 62, 16, 5, 127, 43, 19, 91, 70, 1, 0, 57, 192, + 1, 10, 22, 27, 64, 0, 8, 158, 1, 33, 51, 57, 226, 7, 2, 154, 0, 12, 160, 1, 63, 252, + 127, 92, 160, 1, 18, 49, 92, 41, 93, 128, 0, 15, 160, 1, 9, 15, 128, 0, 17, 4, 24, 16, + 31, 176, 208, 31, 4, 31, 160, 24, 16, 0, 8, 200, 4, 63, 137, 200, 97, 48, 3, 26, 81, + 109, 105, 115, 46, 111, 229, 42, 33, 117, 110, 40, 21, 97, 45, 118, 97, 108, 105, 100, + 132, 9, 22, 46, 183, 13, 13, 112, 1, 49, 255, 18, 98, 144, 2, 15, 136, 11, 9, 8, 144, + 2, 15, 104, 0, 14, 6, 146, 1, 69, 51, 49, 48, 48, 170, 18, 12, 144, 1, 63, 92, 123, 99, + 144, 1, 18, 49, 148, 67, 100, 160, 0, 15, 144, 1, 9, 15, 160, 0, 51, 10, 200, 2, 63, + 91, 253, 103, 128, 1, 26, 242, 12, 111, 110, 108, 105, 110, 101, 45, 97, 117, 116, 104, + 45, 97, 103, 101, 110, 116, 46, 100, 101, 110, 121, 108, 105, 115, 116, 45, 195, 4, 1, + 150, 2, 14, 176, 4, 49, 25, 146, 104, 224, 0, 15, 128, 1, 21, 15, 104, 0, 14, 7, 128, + 1, 79, 48, 53, 55, 50, 128, 1, 5, 63, 228, 74, 107, 128, 1, 18, 49, 164, 8, 108, 160, + 0, 15, 128, 1, 21, 15, 160, 0, 39, 10, 128, 1, 127, 58, 146, 110, 70, 1, 0, 79, 72, 4, + 10, 23, 49, 248, 1, 14, 120, 0, 1, 38, 6, 254, 0, 45, 105, 110, 100, 101, 116, 101, + 114, 109, 105, 110, 97, 116, 101, 115, 128, 1, 32, 22, 214, 104, 0, 31, 96, 112, 4, 10, + 31, 66, 104, 0, 30, 5, 133, 1, 141, 53, 53, 48, 100, 53, 99, 48, 41, 48, 6, 63, 101, + 208, 112, 128, 1, 18, 49, 182, 136, 113, 160, 0, 15, 128, 1, 9, 15, 160, 0, 51, 10, + 128, 1, 49, 224, 80, 117, 0, 20, 15, 176, 7, 9, 8, 0, 20, 242, 7, 105, 99, 108, 111, + 117, 100, 46, 115, 101, 97, 114, 99, 104, 112, 97, 114, 116, 121, 117, 115, 101, 114, + 10, 3, 181, 112, 111, 115, 116, 45, 105, 110, 115, 116, 97, 108, 224, 56, 1, 136, 4, + 22, 243, 32, 28, 34, 144, 159, 112, 0, 47, 221, 165, 136, 12, 3, 31, 66, 112, 0, 49, 7, + 96, 5, 32, 54, 230, 112, 0, 31, 98, 248, 1, 10, 31, 68, 112, 0, 32, 8, 250, 1, 52, 55, + 55, 102, 127, 3, 13, 0, 2, 63, 199, 0, 121, 0, 2, 18, 49, 36, 118, 122, 168, 0, 15, 0, + 2, 9, 15, 168, 0, 59, 10, 8, 2, 127, 176, 210, 125, 70, 1, 0, 65, 136, 3, 10, 2, 108, + 50, 2, 192, 23, 0, 39, 39, 192, 109, 97, 108, 77, 111, 110, 105, 116, 111, 114, 46, 49, + 15, 25, 52, 84, 97, 115, 175, 9, 13, 0, 5, 127, 217, 24, 126, 70, 1, 0, 82, 136, 1, 10, + 31, 52, 96, 0, 16, 5, 120, 1, 95, 55, 51, 49, 51, 57, 120, 1, 7, 63, 63, 110, 127, 120, + 1, 18, 49, 210, 30, 128, 152, 0, 15, 120, 1, 9, 15, 152, 0, 43, 10, 104, 1, 127, 185, + 248, 130, 70, 1, 0, 62, 104, 1, 10, 23, 32, 112, 0, 112, 98, 97, 99, 107, 117, 112, + 100, 113, 6, 129, 111, 46, 100, 114, 121, 115, 112, 101, 93, 3, 12, 96, 1, 49, 130, 66, + 131, 72, 5, 15, 96, 6, 9, 31, 49, 88, 0, 13, 5, 93, 1, 96, 53, 52, 49, 100, 100, 55, + 213, 2, 12, 208, 2, 63, 115, 205, 132, 88, 1, 18, 49, 35, 28, 134, 144, 0, 15, 88, 1, + 9, 15, 144, 0, 35, 10, 80, 1, 127, 152, 248, 137, 70, 1, 0, 53, 80, 1, 10, 31, 23, 104, + 0, 4, 0, 170, 7, 12, 72, 1, 127, 111, 242, 138, 70, 1, 0, 70, 168, 2, 10, 31, 40, 80, + 0, 4, 5, 63, 1, 82, 55, 51, 48, 102, 52, 82, 32, 12, 64, 1, 63, 233, 56, 141, 64, 1, + 18, 32, 39, 255, 40, 0, 31, 70, 184, 33, 10, 15, 136, 0, 27, 10, 56, 1, 49, 69, 93, + 145, 80, 17, 15, 248, 5, 9, 8, 16, 18, 15, 136, 2, 2, 79, 46, 116, 101, 115, 40, 24, 4, + 32, 69, 245, 96, 0, 15, 136, 25, 23, 15, 96, 0, 7, 5, 86, 1, 84, 53, 54, 49, 57, 52, + 251, 11, 12, 88, 1, 63, 196, 58, 147, 88, 1, 18, 32, 143, 231, 40, 0, 31, 84, 88, 1, + 10, 8, 136, 25, 15, 152, 0, 31, 10, 104, 1, 127, 252, 204, 150, 70, 1, 0, 55, 160, 2, + 10, 23, 25, 112, 0, 5, 16, 30, 1, 63, 36, 14, 200, 8, 49, 213, 71, 151, 168, 18, 15, + 232, 3, 9, 8, 168, 18, 10, 80, 0, 5, 76, 1, 111, 55, 51, 48, 99, 101, 48, 176, 8, 0, + 63, 174, 85, 152, 72, 1, 18, 49, 206, 22, 153, 136, 0, 15, 224, 3, 9, 15, 136, 0, 27, + 10, 56, 1, 49, 236, 95, 155, 56, 25, 15, 160, 2, 9, 8, 56, 25, 8, 122, 37, 244, 0, 109, + 105, 99, 114, 111, 115, 116, 97, 99, 107, 115, 104, 111, 116, 95, 3, 1, 1, 169, 2, 12, + 240, 3, 32, 125, 159, 104, 0, 31, 93, 168, 2, 10, 8, 66, 34, 15, 104, 0, 16, 8, 101, 1, + 20, 100, 154, 11, 12, 176, 2, 63, 255, 108, 156, 104, 1, 18, 49, 96, 38, 157, 160, 0, + 15, 104, 1, 9, 15, 160, 0, 51, 10, 128, 1, 63, 168, 218, 159, 16, 8, 26, 1, 176, 28, + 245, 1, 105, 110, 102, 101, 114, 101, 110, 99, 101, 46, 70, 105, 114, 115, 116, 66, 70, + 28, 14, 200, 2, 49, 17, 29, 160, 120, 7, 15, 200, 2, 9, 8, 120, 7, 15, 96, 0, 5, 6, + 109, 1, 67, 49, 49, 56, 54, 29, 35, 1, 216, 5, 10, 208, 20, 63, 231, 4, 162, 112, 1, 2, + 4, 192, 15, 31, 208, 192, 15, 4, 30, 192, 144, 47, 9, 72, 26, 32, 105, 253, 88, 0, 31, + 82, 80, 4, 10, 15, 200, 0, 43, 10, 152, 1, 49, 43, 181, 165, 224, 17, 15, 24, 3, 9, 8, + 208, 33, 49, 68, 105, 102, 148, 1, 241, 2, 116, 105, 97, 108, 80, 114, 105, 118, 97, + 99, 121, 46, 80, 114, 105, 111, 82, 88, 32, 0, 234, 20, 0, 22, 3, 0, 48, 1, 10, 96, 19, + 127, 169, 57, 166, 70, 1, 0, 90, 24, 3, 10, 31, 60, 104, 0, 24, 6, 168, 1, 53, 50, 49, + 52, 78, 31, 0, 120, 0, 10, 168, 1, 63, 216, 56, 167, 168, 1, 2, 0, 184, 3, 8, 120, 1, + 32, 244, 219, 40, 0, 31, 90, 120, 1, 10, 15, 160, 0, 51, 10, 128, 1, 63, 223, 227, 170, + 152, 4, 26, 15, 128, 1, 1, 2, 124, 1, 130, 71, 101, 110, 101, 114, 97, 116, 111, 131, + 1, 0, 224, 0, 8, 128, 1, 49, 108, 40, 171, 248, 3, 15, 32, 3, 9, 8, 248, 3, 15, 104, 0, + 16, 6, 131, 1, 82, 49, 49, 56, 100, 100, 43, 3, 12, 152, 4, 63, 157, 46, 172, 128, 1, + 18, 49, 106, 7, 173, 160, 0, 15, 152, 4, 21, 15, 160, 0, 39, 10, 128, 1, 63, 49, 127, + 175, 128, 1, 46, 106, 68, 101, 68, 105, 115, 99, 3, 3, 12, 128, 1, 32, 17, 194, 104, 0, + 15, 24, 6, 23, 15, 224, 0, 1, 11, 104, 0, 6, 128, 1, 67, 50, 49, 53, 49, 178, 17, 12, + 128, 1, 63, 52, 117, 177, 128, 1, 18, 49, 221, 27, 178, 160, 0, 15, 128, 1, 41, 15, + 160, 0, 19, 10, 128, 1, 127, 45, 175, 180, 70, 1, 0, 88, 208, 8, 10, 23, 58, 18, 45, + 15, 24, 1, 1, 48, 114, 117, 110, 143, 23, 80, 66, 108, 97, 99, 107, 58, 19, 189, 77, + 97, 105, 110, 116, 101, 110, 97, 110, 99, 101, 136, 4, 32, 135, 244, 112, 0, 31, 105, + 136, 1, 10, 31, 75, 112, 0, 39, 6, 148, 1, 82, 49, 49, 57, 57, 53, 148, 1, 0, 145, 3, + 12, 152, 1, 63, 32, 57, 182, 152, 1, 18, 32, 241, 221, 40, 0, 31, 105, 152, 4, 10, 15, + 176, 0, 67, 10, 168, 1, 63, 140, 237, 184, 88, 19, 26, 15, 168, 1, 1, 48, 83, 116, 111, + 218, 17, 8, 159, 1, 13, 160, 1, 49, 217, 137, 185, 184, 18, 15, 168, 4, 9, 8, 184, 18, + 15, 104, 0, 19, 6, 151, 1, 64, 50, 49, 53, 57, 171, 4, 12, 144, 1, 63, 207, 146, 186, + 144, 1, 18, 49, 234, 56, 187, 160, 0, 15, 40, 3, 9, 15, 160, 0, 51, 10, 128, 1, 127, + 151, 218, 189, 70, 1, 0, 75, 40, 3, 10, 31, 45, 120, 0, 19, 112, 67, 117, 108, 108, + 105, 110, 103, 150, 2, 0, 48, 7, 10, 168, 7, 127, 246, 96, 190, 70, 1, 0, 92, 32, 3, + 10, 8, 250, 36, 15, 128, 1, 8, 3, 104, 0, 6, 124, 1, 49, 49, 49, 97, 212, 20, 0, 122, + 0, 12, 128, 1, 63, 223, 6, 192, 128, 1, 18, 32, 194, 176, 40, 0, 31, 92, 16, 3, 10, 15, + 160, 0, 51, 10, 128, 1, 49, 16, 228, 195, 232, 44, 15, 40, 9, 9, 8, 232, 44, 15, 24, 1, + 1, 3, 48, 9, 105, 66, 117, 100, 103, 101, 116, 6, 3, 14, 136, 1, 127, 149, 43, 196, 70, + 1, 0, 102, 136, 1, 10, 31, 72, 112, 0, 36, 5, 146, 1, 67, 53, 52, 49, 101, 237, 31, 12, + 144, 1, 63, 117, 127, 197, 144, 1, 18, 49, 80, 40, 198, 168, 0, 15, 16, 3, 9, 15, 168, + 0, 59, 10, 152, 1, 49, 119, 57, 200, 48, 11, 15, 152, 1, 9, 8, 48, 11, 15, 152, 1, 1, + 101, 115, 101, 114, 118, 101, 114, 63, 6, 2, 67, 44, 0, 165, 2, 1, 168, 2, 10, 32, 3, + 32, 160, 126, 112, 0, 31, 99, 152, 1, 10, 31, 69, 112, 0, 33, 5, 149, 1, 82, 55, 49, + 49, 98, 50, 149, 1, 1, 128, 0, 10, 208, 10, 63, 107, 230, 201, 152, 1, 18, 49, 153, + 158, 202, 168, 0, 15, 152, 1, 9, 15, 168, 0, 59, 10, 152, 1, 127, 158, 69, 205, 70, 1, + 0, 83, 176, 4, 10, 31, 53, 128, 0, 12, 2, 81, 9, 91, 70, 105, 108, 101, 115, 46, 3, 0, + 24, 1, 10, 152, 1, 32, 72, 201, 112, 0, 31, 100, 152, 1, 10, 31, 70, 112, 0, 34, 5, + 153, 1, 83, 53, 52, 49, 56, 48, 103, 9, 13, 48, 3, 63, 159, 2, 207, 152, 1, 18, 32, + 165, 194, 40, 0, 31, 100, 192, 4, 10, 15, 168, 0, 59, 10, 152, 1, 127, 161, 65, 210, + 70, 1, 0, 63, 152, 1, 10, 23, 33, 128, 0, 80, 112, 111, 119, 101, 114, 148, 41, 146, + 100, 46, 51, 104, 111, 117, 114, 108, 121, 150, 23, 12, 184, 7, 32, 25, 194, 88, 0, 31, + 80, 128, 1, 10, 31, 50, 88, 0, 14, 5, 108, 1, 0, 80, 18, 47, 53, 57, 168, 7, 0, 63, 48, + 16, 212, 104, 1, 18, 32, 159, 171, 40, 0, 31, 80, 104, 1, 10, 15, 144, 0, 33, 4, 224, + 15, 34, 0, 16, 32, 4, 17, 117, 6, 0, 51, 0, 0, 253, 8, 0, 12, 136, 85, 162, 4, 0, 2, 2, + 128, 245, 9, 0, 185, 2, 33, 0, 32, 148, 124, 160, 31, 115, 8, 0, 140, 218, 7, 0, 1, + 200, 57, 68, 128, 250, 63, 18, 32, 0, 161, 79, 179, 74, 72, 1, 0, 12, 0, 112, 6, 47, 0, + 80, 128, 107, 149, 59, 18, 9, 0, 87, 4, 0, 5, 2, 176, 40, 0, 32, 108, 239, 40, 0, 21, + 50, 40, 0, 215, 204, 149, 59, 18, 4, 0, 34, 1, 64, 4, 0, 0, 28, 216, 0, 144, 99, 111, + 114, 101, 100, 117, 101, 116, 100, 195, 62, 22, 116, 129, 85, 0, 120, 0, 38, 96, 254, + 120, 0, 49, 69, 56, 129, 120, 0, 19, 113, 120, 0, 34, 242, 166, 120, 0, 0, 40, 0, 68, + 0, 85, 240, 3, 160, 0, 49, 233, 100, 241, 40, 0, 19, 114, 40, 0, 64, 128, 29, 210, 3, + 160, 0, 12, 40, 0, 64, 128, 239, 176, 75, 200, 0, 31, 115, 40, 0, 0, 8, 120, 0, 49, + 252, 97, 206, 40, 0, 19, 116, 40, 0, 8, 120, 0, 38, 224, 255, 160, 0, 49, 19, 65, 213, + 40, 0, 19, 117, 40, 0, 49, 194, 232, 61, 160, 0, 0, 24, 1, 53, 16, 0, 64, 40, 0, 32, + 47, 101, 40, 0, 21, 76, 40, 0, 53, 64, 233, 61, 24, 1, 8, 136, 21, 0, 20, 1, 1, 238, + 40, 241, 14, 105, 116, 121, 115, 99, 104, 101, 100, 117, 108, 101, 114, 46, 119, 105, + 102, 105, 113, 117, 97, 108, 105, 116, 121, 112, 114, 101, 100, 105, 102, 83, 0, 223, + 0, 176, 0, 2, 1, 21, 2, 208, 1, 64, 18, 107, 5, 14, 0, 149, 0, 0, 160, 125, 247, 75, 1, + 0, 36, 104, 0, 18, 117, 23, 0, 5, 16, 0, 19, 118, 128, 0, 39, 91, 253, 168, 0, 22, 2, + 64, 0, 32, 123, 251, 64, 0, 36, 22, 0, 40, 0, 32, 170, 253, 168, 0, 66, 35, 1, 65, 4, + 73, 0, 12, 80, 1, 49, 31, 233, 253, 0, 1, 19, 119, 48, 0, 15, 120, 1, 5, 64, 6, 4, 79, + 76, 120, 1, 31, 120, 40, 0, 12, 49, 0, 141, 195, 40, 0, 31, 121, 40, 0, 12, 49, 253, + 186, 224, 40, 0, 27, 122, 40, 0, 117, 4, 16, 4, 2, 32, 58, 241, 24, 2, 64, 218, 90, 22, + 77, 21, 71, 80, 239, 32, 237, 3, 9, 184, 6, 86, 16, 4, 2, 64, 37, 56, 2, 49, 20, 216, + 28, 32, 0, 83, 168, 161, 234, 3, 11, 48, 2, 8, 224, 1, 64, 25, 7, 35, 77, 184, 0, 19, + 123, 104, 0, 15, 224, 1, 5, 32, 178, 16, 40, 0, 21, 57, 40, 0, 8, 224, 1, 8, 80, 28, + 48, 100, 97, 115, 4, 56, 96, 112, 111, 108, 105, 99, 121, 10, 0, 113, 99, 104, 97, 110, + 103, 101, 100, 93, 1, 15, 128, 0, 0, 49, 234, 35, 39, 128, 0, 19, 124, 88, 0, 15, 128, + 0, 5, 32, 186, 45, 40, 0, 21, 57, 40, 0, 15, 128, 0, 22, 101, 73, 110, 70, 111, 99, + 117, 0, 37, 0, 224, 1, 8, 0, 1, 49, 106, 112, 40, 128, 0, 19, 125, 88, 0, 15, 128, 0, + 5, 32, 183, 118, 40, 0, 21, 92, 40, 0, 8, 128, 0, 8, 56, 6, 15, 224, 2, 3, 195, 98, 97, + 116, 116, 101, 114, 121, 108, 101, 118, 101, 108, 27, 1, 8, 19, 0, 2, 36, 1, 1, 163, 0, + 12, 160, 0, 49, 1, 132, 41, 160, 0, 19, 126, 120, 0, 15, 160, 0, 5, 32, 178, 137, 40, + 0, 21, 90, 40, 0, 8, 160, 0, 8, 112, 30, 15, 160, 0, 3, 32, 99, 97, 155, 12, 131, 112, + 114, 111, 103, 114, 101, 115, 115, 162, 0, 10, 21, 0, 0, 157, 0, 15, 192, 1, 0, 49, + 164, 100, 42, 160, 0, 19, 127, 120, 0, 15, 160, 0, 5, 32, 89, 107, 40, 0, 21, 85, 40, + 0, 8, 160, 0, 8, 0, 19, 15, 160, 0, 5, 85, 114, 112, 108, 97, 121, 153, 0, 1, 14, 0, + 114, 99, 111, 110, 110, 101, 99, 116, 92, 2, 12, 56, 1, 49, 166, 155, 43, 152, 0, 19, + 128, 112, 0, 15, 152, 0, 5, 32, 249, 161, 40, 0, 21, 89, 40, 0, 8, 152, 0, 31, 67, 152, + 0, 15, 116, 112, 117, 117, 115, 97, 103, 101, 153, 0, 3, 15, 0, 1, 232, 1, 7, 213, 1, + 15, 56, 1, 0, 49, 49, 106, 44, 160, 0, 19, 129, 120, 0, 15, 160, 0, 5, 32, 109, 110, + 40, 0, 21, 87, 40, 0, 8, 160, 0, 8, 192, 46, 15, 56, 1, 3, 211, 100, 101, 102, 97, 117, + 108, 116, 112, 97, 105, 114, 101, 100, 165, 0, 96, 110, 101, 97, 114, 98, 121, 160, 59, + 0, 22, 3, 12, 56, 1, 49, 200, 54, 45, 152, 0, 19, 130, 112, 0, 15, 152, 0, 5, 32, 35, + 59, 40, 0, 21, 87, 40, 0, 15, 152, 0, 29, 68, 118, 105, 99, 101, 8, 6, 3, 153, 0, 95, + 105, 110, 117, 115, 101, 152, 0, 5, 32, 7, 219, 112, 0, 51, 12, 0, 131, 112, 0, 15, + 152, 0, 5, 32, 112, 222, 40, 0, 21, 80, 40, 0, 8, 152, 0, 8, 208, 18, 15, 48, 1, 3, 0, + 203, 21, 49, 103, 121, 98, 41, 14, 3, 150, 0, 3, 145, 0, 12, 40, 1, 49, 193, 120, 46, + 144, 0, 31, 132, 144, 0, 12, 32, 44, 124, 40, 0, 21, 71, 40, 0, 8, 144, 0, 24, 49, 144, + 0, 193, 97, 115, 46, 102, 105, 108, 101, 112, 114, 111, 116, 101, 255, 6, 9, 128, 0, 2, + 77, 2, 30, 100, 72, 2, 49, 128, 8, 47, 136, 0, 19, 133, 96, 0, 15, 24, 1, 5, 32, 150, + 11, 40, 0, 21, 73, 40, 0, 8, 136, 0, 8, 168, 35, 0, 192, 5, 15, 136, 0, 2, 34, 107, 98, + 10, 1, 5, 138, 0, 15, 16, 4, 3, 32, 82, 175, 104, 0, 51, 12, 0, 134, 104, 0, 15, 144, + 0, 5, 32, 163, 178, 40, 0, 21, 68, 40, 0, 8, 144, 0, 24, 46, 144, 0, 15, 168, 1, 2, 34, + 110, 119, 141, 0, 1, 57, 8, 15, 136, 0, 2, 49, 252, 172, 48, 136, 0, 31, 135, 136, 0, + 12, 32, 173, 178, 40, 0, 21, 69, 40, 0, 8, 136, 0, 31, 47, 136, 0, 25, 31, 114, 136, 4, + 3, 49, 233, 120, 49, 136, 0, 19, 136, 96, 0, 15, 16, 1, 5, 32, 106, 125, 40, 0, 21, 78, + 40, 0, 8, 136, 0, 8, 192, 52, 83, 100, 117, 101, 97, 116, 56, 3, 6, 64, 9, 84, 112, + 104, 111, 116, 111, 184, 5, 2, 13, 0, 0, 244, 73, 15, 120, 4, 0, 49, 216, 108, 50, 144, + 0, 19, 137, 104, 0, 15, 144, 0, 5, 32, 117, 115, 40, 0, 21, 82, 40, 0, 8, 144, 0, 26, + 60, 144, 0, 20, 116, 200, 3, 15, 144, 0, 4, 2, 79, 3, 128, 79, 118, 101, 114, 114, 105, + 100, 101, 173, 1, 15, 152, 0, 0, 49, 64, 116, 51, 152, 0, 19, 138, 112, 0, 15, 152, 0, + 5, 32, 69, 122, 40, 0, 21, 78, 40, 0, 8, 152, 0, 11, 40, 1, 15, 152, 0, 13, 9, 157, 8, + 12, 224, 3, 49, 2, 90, 52, 144, 0, 19, 139, 104, 0, 15, 144, 0, 5, 32, 54, 94, 40, 0, + 21, 82, 40, 0, 8, 144, 0, 15, 40, 1, 16, 116, 108, 117, 103, 103, 101, 100, 105, 237, + 3, 37, 105, 115, 18, 0, 2, 39, 1, 13, 152, 0, 49, 181, 25, 53, 152, 0, 19, 140, 112, 0, + 15, 152, 0, 5, 32, 102, 29, 40, 0, 21, 83, 40, 0, 8, 152, 0, 31, 61, 152, 0, 14, 16, + 114, 136, 5, 35, 114, 116, 150, 0, 80, 97, 115, 115, 101, 114, 147, 4, 67, 115, 104, + 101, 108, 202, 9, 12, 152, 0, 49, 127, 0, 54, 152, 0, 19, 141, 112, 0, 15, 152, 0, 5, + 32, 92, 6, 40, 0, 21, 80, 40, 0, 8, 152, 0, 15, 160, 5, 15, 10, 152, 0, 8, 49, 6, 12, + 144, 0, 49, 176, 13, 55, 144, 0, 19, 142, 104, 0, 15, 144, 0, 5, 32, 63, 19, 40, 0, 21, + 62, 40, 0, 8, 144, 0, 8, 152, 35, 0, 24, 5, 10, 126, 0, 0, 82, 34, 127, 108, 105, 103, + 104, 116, 79, 110, 208, 2, 0, 32, 80, 193, 88, 0, 51, 12, 0, 143, 88, 0, 15, 128, 0, 5, + 32, 186, 197, 40, 0, 21, 80, 40, 0, 8, 128, 0, 15, 16, 1, 29, 67, 119, 97, 107, 101, + 157, 97, 13, 56, 2, 49, 122, 82, 56, 144, 0, 31, 144, 144, 0, 12, 32, 249, 85, 40, 0, + 21, 96, 40, 0, 8, 144, 0, 31, 74, 144, 0, 14, 3, 78, 40, 2, 56, 2, 2, 6, 0, 5, 20, 0, + 0, 90, 10, 50, 117, 114, 101, 64, 6, 13, 216, 13, 64, 11, 238, 70, 77, 216, 13, 4, 96, + 12, 4, 216, 13, 4, 16, 0, 19, 145, 8, 0, 4, 216, 13, 4, 16, 16, 19, 224, 240, 31, 4, + 48, 0, 4, 16, 16, 29, 208, 16, 16, 10, 8, 14, 132, 24, 20, 71, 77, 1, 0, 22, 0, 88, 0, + 15, 8, 14, 1, 8, 48, 15, 49, 225, 115, 90, 64, 1, 19, 146, 48, 0, 6, 48, 15, 2, 160, + 14, 34, 102, 5, 121, 0, 49, 66, 23, 98, 200, 0, 4, 40, 12, 4, 152, 0, 4, 16, 0, 19, + 147, 8, 0, 4, 200, 0, 1, 72, 15, 22, 2, 64, 0, 32, 84, 39, 64, 0, 36, 22, 0, 40, 0, 15, + 152, 0, 1, 38, 48, 2, 120, 15, 49, 128, 167, 106, 152, 0, 19, 148, 48, 0, 34, 243, 254, + 248, 14, 4, 96, 1, 4, 88, 0, 49, 161, 42, 111, 152, 0, 4, 32, 12, 4, 152, 0, 4, 16, 0, + 19, 149, 8, 0, 15, 152, 0, 5, 32, 213, 48, 64, 0, 36, 22, 0, 40, 0, 15, 152, 0, 1, 8, + 48, 1, 49, 10, 138, 117, 152, 0, 19, 150, 48, 0, 6, 48, 1, 10, 40, 0, 49, 238, 58, 123, + 40, 0, 29, 151, 40, 0, 10, 88, 1, 49, 202, 30, 127, 192, 0, 4, 64, 12, 4, 192, 0, 4, + 16, 0, 19, 152, 8, 0, 15, 192, 0, 5, 32, 116, 36, 64, 0, 36, 22, 0, 40, 0, 14, 192, 0, + 10, 112, 0, 49, 250, 64, 140, 112, 0, 4, 24, 12, 4, 112, 0, 4, 16, 0, 19, 153, 8, 0, + 15, 112, 0, 5, 32, 188, 70, 64, 0, 36, 22, 0, 40, 0, 12, 112, 0, 102, 4, 1, 2, 2, 128, + 164, 160, 18, 161, 248, 162, 145, 77, 1, 0, 18, 0, 3, 171, 227, 18, 0, 211, 15, 3, 114, + 0, 2, 6, 0, 0, 208, 3, 8, 248, 1, 49, 117, 188, 149, 56, 1, 19, 154, 96, 0, 4, 248, 1, + 0, 88, 0, 83, 224, 158, 9, 0, 118, 248, 1, 240, 1, 237, 125, 153, 77, 1, 0, 20, 0, 181, + 96, 0, 0, 17, 0, 34, 2, 168, 18, 0, 39, 16, 0, 4, 19, 0, 3, 0, 12, 40, 2, 49, 14, 233, + 156, 248, 0, 4, 112, 12, 4, 248, 0, 4, 16, 0, 19, 155, 8, 0, 15, 248, 0, 5, 32, 234, + 238, 64, 0, 36, 22, 0, 40, 0, 12, 248, 0, 12, 200, 0, 49, 143, 191, 160, 200, 0, 19, + 156, 48, 0, 4, 200, 0, 12, 152, 0, 49, 118, 177, 174, 152, 0, 4, 0, 16, 4, 152, 0, 4, + 16, 0, 19, 157, 8, 0, 15, 152, 0, 5, 32, 157, 183, 64, 0, 36, 22, 0, 40, 0, 14, 152, 0, + 10, 0, 2, 49, 27, 29, 188, 112, 0, 4, 224, 12, 4, 112, 0, 4, 16, 0, 19, 158, 8, 0, 15, + 112, 0, 5, 32, 21, 35, 64, 0, 36, 22, 0, 40, 0, 15, 112, 0, 13, 49, 23, 211, 200, 112, + 0, 19, 131, 48, 0, 4, 112, 0, 4, 16, 0, 19, 159, 8, 0, 15, 112, 0, 5, 32, 12, 217, 64, + 0, 36, 22, 0, 40, 0, 15, 112, 0, 13, 49, 131, 218, 215, 112, 0, 4, 152, 12, 4, 112, 0, + 4, 16, 0, 19, 192, 8, 0, 15, 112, 0, 5, 32, 161, 224, 64, 0, 36, 22, 0, 40, 0, 15, 112, + 0, 13, 49, 235, 171, 235, 112, 0, 4, 128, 12, 4, 112, 0, 4, 16, 0, 19, 193, 8, 0, 15, + 112, 0, 5, 32, 125, 178, 64, 0, 36, 22, 0, 40, 0, 15, 112, 0, 13, 49, 155, 252, 247, + 112, 0, 4, 136, 12, 4, 112, 0, 4, 16, 0, 19, 194, 8, 0, 15, 112, 0, 5, 49, 86, 3, 248, + 112, 0, 4, 40, 0, 14, 112, 0, 2, 160, 21, 4, 104, 3, 49, 227, 84, 252, 200, 2, 19, 195, + 48, 0, 12, 40, 20, 4, 192, 20, 34, 252, 107, 40, 0, 29, 196, 40, 0, 10, 128, 2, 64, 7, + 233, 5, 78, 16, 7, 4, 152, 12, 4, 192, 0, 4, 16, 0, 19, 197, 8, 0, 15, 192, 0, 5, 32, + 145, 239, 64, 0, 36, 22, 0, 40, 0, 14, 192, 0, 10, 112, 0, 49, 164, 184, 19, 112, 0, 4, + 128, 12, 4, 112, 0, 4, 16, 0, 19, 198, 8, 0, 15, 112, 0, 5, 32, 220, 190, 64, 0, 36, + 22, 0, 40, 0, 15, 112, 0, 13, 49, 189, 242, 33, 112, 0, 4, 96, 12, 4, 112, 0, 4, 16, 0, + 19, 199, 8, 0, 15, 112, 0, 5, 32, 236, 249, 64, 0, 36, 22, 0, 40, 0, 12, 112, 0, 0, 8, + 5, 38, 48, 159, 8, 5, 64, 47, 91, 34, 78, 96, 5, 32, 178, 101, 8, 5, 81, 0, 1, 0, 8, + 170, 1, 0, 34, 240, 63, 121, 0, 0, 48, 0, 38, 16, 160, 48, 0, 160, 222, 200, 35, 78, 1, + 0, 24, 0, 102, 103, 48, 0, 35, 35, 2, 32, 22, 3, 54, 0, 32, 32, 65, 48, 0, 8, 96, 0, + 32, 2, 211, 48, 0, 15, 96, 0, 23, 32, 199, 219, 48, 0, 14, 96, 0, 1, 141, 0, 15, 152, + 5, 0, 49, 30, 180, 53, 48, 1, 4, 104, 12, 4, 48, 1, 4, 16, 0, 19, 200, 8, 0, 15, 48, 1, + 5, 32, 79, 186, 64, 0, 36, 22, 0, 40, 0, 12, 48, 1, 12, 112, 5, 49, 240, 41, 79, 112, + 0, 4, 64, 12, 4, 112, 0, 4, 16, 0, 19, 201, 8, 0, 15, 112, 0, 5, 32, 142, 48, 64, 0, + 36, 22, 0, 40, 0, 15, 112, 0, 13, 49, 217, 182, 102, 112, 0, 4, 24, 12, 4, 112, 0, 4, + 16, 0, 19, 202, 8, 0, 15, 112, 0, 5, 32, 163, 188, 64, 0, 36, 22, 0, 40, 0, 15, 112, 0, + 13, 49, 117, 246, 124, 112, 0, 4, 248, 11, 4, 112, 0, 4, 16, 0, 19, 203, 8, 0, 15, 112, + 0, 5, 32, 41, 253, 64, 0, 36, 22, 0, 40, 0, 15, 112, 0, 13, 49, 97, 246, 143, 112, 0, + 4, 16, 12, 4, 112, 0, 4, 16, 0, 19, 204, 8, 0, 15, 112, 0, 5, 32, 162, 251, 64, 0, 36, + 22, 0, 40, 0, 15, 112, 0, 13, 49, 153, 190, 160, 112, 0, 4, 40, 15, 4, 112, 0, 4, 16, + 0, 19, 205, 8, 0, 15, 112, 0, 5, 32, 205, 196, 64, 0, 36, 22, 0, 40, 0, 15, 112, 0, 13, + 64, 149, 171, 16, 79, 176, 4, 4, 56, 12, 4, 112, 0, 4, 16, 0, 19, 206, 8, 0, 15, 112, + 0, 5, 32, 219, 178, 64, 0, 36, 22, 0, 40, 0, 12, 112, 0, 0, 248, 29, 53, 160, 97, 7, + 48, 9, 64, 213, 17, 70, 79, 24, 73, 83, 188, 105, 5, 0, 28, 50, 104, 120, 30, 0, 34, 4, + 30, 0, 9, 166, 12, 16, 97, 193, 81, 54, 97, 116, 97, 91, 95, 20, 0, 104, 56, 2, 161, 0, + 0, 88, 0, 38, 176, 100, 88, 0, 161, 67, 118, 76, 79, 1, 0, 64, 0, 64, 114, 88, 0, 16, + 3, 80, 67, 198, 30, 0, 0, 8, 144, 23, 97, 152, 145, 127, 0, 0, 152, 9, 6, 28, 39, 15, + 102, 0, 1, 0, 88, 0, 23, 224, 176, 0, 32, 75, 121, 88, 0, 79, 69, 0, 12, 116, 88, 0, 3, + 15, 186, 0, 29, 0, 96, 0, 8, 16, 1, 32, 10, 254, 96, 0, 25, 63, 16, 1, 94, 34, 0, 34, + 4, 34, 16, 1, 80, 97, 110, 97, 108, 121, 154, 81, 2, 232, 31, 55, 105, 110, 103, 20, 1, + 0, 88, 0, 8, 16, 1, 64, 107, 71, 77, 79, 0, 82, 8, 16, 1, 111, 34, 0, 0, 8, 80, 9, 16, + 1, 12, 15, 102, 0, 0, 0, 113, 1, 0, 96, 0, 8, 24, 1, 32, 211, 72, 96, 0, 25, 73, 24, 1, + 8, 96, 0, 15, 194, 0, 31, 0, 102, 0, 0, 168, 32, 10, 32, 1, 121, 180, 15, 78, 79, 1, 0, + 57, 32, 1, 94, 28, 0, 34, 4, 28, 32, 1, 128, 111, 118, 101, 114, 100, 117, 101, 67, + 144, 58, 7, 26, 1, 1, 87, 0, 1, 88, 0, 8, 32, 1, 32, 155, 23, 88, 0, 25, 62, 48, 2, + 111, 28, 0, 0, 8, 64, 39, 32, 1, 12, 9, 102, 0, 2, 176, 0, 8, 24, 1, 32, 252, 24, 88, + 0, 25, 67, 24, 1, 8, 88, 0, 15, 186, 0, 29, 0, 184, 0, 68, 32, 98, 7, 0, 16, 14, 32, + 21, 153, 96, 0, 79, 69, 0, 123, 119, 144, 2, 55, 38, 224, 100, 96, 0, 34, 186, 160, 96, + 0, 47, 69, 253, 96, 0, 51, 4, 240, 15, 19, 48, 240, 15, 3, 135, 18, 35, 0, 251, 8, 0, + 29, 32, 240, 15, 2, 0, 2, 34, 182, 2, 32, 0, 68, 183, 59, 100, 74, 48, 4, 31, 7, 48, 4, + 6, 6, 182, 31, 0, 239, 64, 91, 108, 101, 100, 103, 101, 2, 2, 0, 72, 1, 0, 0, 2, 4, 88, + 0, 68, 115, 162, 130, 74, 48, 4, 23, 7, 48, 4, 95, 64, 173, 192, 210, 240, 48, 4, 4, + 15, 102, 0, 1, 0, 88, 0, 0, 0, 2, 4, 88, 0, 32, 29, 165, 88, 0, 17, 69, 0, 2, 15, 88, + 0, 1, 12, 48, 4, 15, 84, 0, 1, 8, 188, 2, 0, 96, 0, 0, 0, 2, 33, 103, 5, 15, 1, 65, 0, + 179, 117, 131, 96, 0, 0, 0, 2, 15, 96, 0, 53, 0, 0, 2, 4, 96, 0, 34, 68, 123, 96, 0, 0, + 0, 2, 15, 96, 0, 53, 38, 160, 99, 96, 0, 49, 220, 12, 133, 120, 1, 47, 131, 120, 96, 0, + 3, 15, 168, 5, 1, 15, 36, 1, 1, 1, 24, 1, 22, 106, 88, 0, 34, 251, 14, 88, 0, 63, 230, + 222, 6, 88, 0, 46, 23, 160, 88, 0, 32, 125, 16, 88, 0, 65, 74, 0, 27, 138, 176, 0, 20, + 4, 88, 6, 14, 40, 2, 15, 186, 0, 21, 1, 199, 1, 5, 56, 4, 4, 24, 1, 32, 41, 38, 104, 0, + 31, 65, 56, 2, 10, 23, 5, 34, 7, 15, 20, 1, 1, 0, 128, 33, 1, 93, 0, 3, 176, 5, 38, 0, + 107, 32, 1, 32, 3, 51, 96, 0, 63, 74, 0, 174, 200, 0, 64, 23, 32, 48, 1, 17, 254, 104, + 0, 15, 136, 1, 9, 4, 194, 16, 6, 136, 7, 15, 204, 0, 1, 0, 32, 1, 8, 248, 2, 32, 122, + 57, 192, 0, 17, 65, 248, 4, 15, 56, 2, 1, 0, 88, 3, 15, 32, 1, 29, 8, 248, 2, 34, 52, + 59, 96, 0, 15, 248, 2, 9, 15, 96, 0, 29, 38, 32, 101, 128, 1, 32, 129, 61, 96, 0, 65, + 54, 0, 199, 254, 72, 2, 1, 42, 113, 0, 160, 8, 3, 55, 4, 15, 90, 0, 12, 2, 208, 1, 23, + 160, 104, 4, 32, 6, 108, 80, 0, 17, 69, 24, 7, 4, 24, 5, 89, 40, 0, 34, 4, 40, 24, 7, + 6, 90, 1, 0, 147, 38, 6, 9, 119, 89, 46, 116, 97, 115, 107, 34, 5, 0, 112, 1, 8, 32, 5, + 49, 93, 98, 137, 48, 2, 0, 64, 8, 4, 112, 1, 127, 40, 0, 0, 8, 192, 255, 224, 32, 5, + 16, 15, 110, 0, 1, 2, 233, 0, 0, 104, 0, 8, 48, 5, 32, 32, 113, 104, 0, 25, 79, 248, 2, + 8, 104, 0, 15, 210, 0, 37, 0, 104, 0, 8, 120, 4, 32, 107, 118, 104, 0, 15, 120, 4, 9, + 15, 152, 2, 24, 7, 240, 2, 34, 69, 121, 88, 0, 15, 240, 2, 61, 32, 31, 159, 88, 0, 25, + 79, 240, 2, 15, 24, 1, 53, 8, 248, 2, 34, 139, 162, 104, 0, 8, 248, 2, 15, 104, 0, 53, + 8, 128, 1, 49, 115, 240, 139, 80, 2, 8, 128, 1, 8, 104, 0, 15, 62, 5, 11, 15, 80, 2, + 11, 8, 128, 4, 34, 224, 242, 104, 0, 8, 144, 1, 15, 104, 0, 53, 8, 24, 6, 32, 127, 244, + 104, 0, 25, 84, 24, 6, 15, 104, 0, 3, 15, 218, 0, 35, 0, 192, 2, 0, 40, 3, 4, 32, 6, + 32, 45, 255, 112, 0, 31, 75, 40, 3, 10, 15, 160, 4, 3, 15, 60, 1, 1, 6, 42, 6, 0, 104, + 0, 8, 40, 6, 49, 107, 12, 140, 216, 0, 8, 40, 6, 15, 216, 0, 61, 8, 176, 1, 32, 146, + 13, 112, 0, 25, 74, 48, 6, 10, 112, 0, 15, 152, 3, 9, 15, 220, 0, 1, 2, 47, 0, 0, 216, + 0, 8, 64, 6, 32, 145, 17, 104, 0, 31, 75, 80, 3, 10, 15, 64, 1, 37, 8, 80, 3, 34, 217, + 19, 104, 0, 15, 80, 3, 9, 15, 104, 0, 37, 8, 80, 6, 32, 105, 22, 104, 0, 25, 64, 80, 6, + 0, 56, 1, 15, 80, 6, 9, 15, 46, 1, 1, 0, 40, 1, 8, 168, 3, 49, 34, 4, 143, 144, 1, 15, + 168, 3, 7, 15, 144, 1, 40, 7, 248, 1, 34, 193, 6, 104, 0, 15, 168, 3, 7, 15, 104, 0, + 39, 68, 192, 136, 79, 7, 144, 11, 64, 138, 69, 229, 74, 192, 106, 83, 88, 100, 72, 7, + 11, 72, 25, 119, 33, 0, 64, 4, 33, 0, 20, 134, 1, 0, 84, 69, 3, 196, 118, 23, 45, 134, + 80, 15, 149, 7, 0, 3, 149, 0, 1, 144, 7, 8, 104, 0, 32, 207, 101, 104, 0, 64, 56, 0, + 136, 104, 104, 0, 17, 35, 176, 25, 34, 36, 0, 126, 20, 6, 71, 0, 16, 100, 97, 38, 16, + 111, 148, 98, 243, 10, 97, 112, 115, 45, 101, 110, 118, 105, 114, 111, 110, 109, 101, + 110, 116, 0, 4, 16, 5, 2, 0, 197, 240, 3, 104, 240, 3, 64, 244, 98, 109, 75, 147, 114, + 19, 114, 88, 17, 64, 13, 56, 236, 3, 11, 0, 0, 40, 0, 23, 64, 40, 0, 117, 156, 250, + 195, 75, 1, 0, 40, 56, 44, 17, 188, 40, 0, 2, 48, 26, 64, 5, 0, 64, 4, 110, 8, 189, 50, + 51, 54, 56, 0, 50, 53, 57, 50, 48, 48, 104, 0, 64, 207, 121, 22, 76, 104, 0, 19, 119, + 64, 0, 12, 104, 0, 19, 105, 144, 0, 64, 8, 196, 26, 78, 104, 0, 4, 40, 23, 15, 104, 0, + 15, 100, 4, 2, 0, 152, 139, 32, 136, 1, 211, 211, 106, 205, 79, 1, 0, 47, 1, 28, 182, + 138, 32, 19, 136, 1, 140, 107, 0, 64, 4, 107, 0, 176, 0, 224, 111, 1, 248, 51, 112, + 116, 101, 70, 114, 97, 109, 101, 15, 35, 244, 4, 115, 47, 80, 101, 111, 112, 108, 101, + 83, 117, 103, 103, 101, 115, 116, 101, 114, 46, 102, 27, 0, 22, 47, 92, 1, 12, 36, 0, + 18, 67, 131, 108, 18, 68, 75, 39, 32, 46, 112, 234, 56, 17, 0, 111, 128, 6, 131, 128, + 81, 67, 111, 99, 111, 97, 20, 0, 2, 19, 0, 160, 32, 67, 111, 100, 101, 61, 50, 54, 48, + 32, 110, 113, 128, 73, 110, 102, 111, 61, 123, 78, 83, 82, 49, 114, 80, 97, 116, 104, + 61, 60, 112, 154, 0, 241, 0, 62, 44, 32, 78, 83, 85, 110, 100, 101, 114, 108, 121, 105, + 110, 103, 65, 0, 241, 2, 61, 48, 120, 55, 102, 102, 48, 100, 50, 100, 50, 97, 54, 51, + 48, 32, 123, 22, 0, 6, 107, 0, 15, 238, 128, 32, 38, 125, 125, 64, 15, 0, 93, 28, 0, + 123, 2, 16, 183, 5, 0, 67, 0, 0, 0, 118, 31, 3, 15, 64, 47, 1, 81, 32, 16, 11, 0, 94, + 122, 2, 96, 0, 0, 181, 109, 135, 55, 48, 58, 176, 81, 205, 4, 0, 1, 0, 34, 8, 0, 4, 7, + 57, 0, 1, 30, 0, 0, 132, 10, 0, 3, 0, 245, 52, 255, 255, 255, 255, 18, 4, 24, 0, 0, 0, + 242, 4, 4, 0, 16, 0, 34, 4, 20, 0, 5, 0, 34, 4, 25, 0, 7, 0, 97, 100, 100, 0, 150, 28, + 37, 76, 95, 164, 125, 139, 226, 48, 91, 94, 206, 4, 152, 167, 65, 65, 65, 65, 0, 109, + 111, 114, 116, 97, 108, 0, 4, 0, 2, 2, 96, 247, 10, 112, 0, 32, 246, 146, 112, 0, 80, + 59, 0, 82, 229, 3, 112, 0, 24, 5, 112, 0, 4, 100, 0, 0, 42, 29, 94, 34, 4, 16, 0, 5, + 90, 0, 48, 100, 100, 114, 154, 0, 0, 240, 10, 10, 200, 0, 32, 67, 150, 88, 0, 31, 85, + 200, 0, 30, 95, 2, 0, 34, 4, 22, 200, 0, 5, 4, 197, 0, 0, 88, 3, 146, 0, 2, 2, 176, 17, + 11, 0, 224, 3, 128, 0, 64, 102, 191, 140, 55, 136, 70, 33, 248, 212, 56, 1, 3, 200, 0, + 0, 50, 1, 64, 1, 0, 242, 4, 50, 3, 50, 0, 8, 152, 43, 0, 243, 11, 0, 34, 4, 17, 0, 11, + 0, 0, 185, 12, 175, 222, 81, 186, 11, 109, 246, 114, 61, 166, 84, 92, 155, 236, 115, + 121, 218, 37, 0, 244, 16, 0, 40, 1, 38, 32, 12, 96, 0, 161, 68, 48, 158, 56, 1, 0, 95, + 0, 13, 179, 96, 0, 49, 9, 0, 4, 39, 8, 82, 4, 0, 208, 0, 192, 146, 1, 2, 164, 1, 6, 46, + 1, 29, 1, 114, 0, 0, 76, 18, 29, 1, 119, 0, 29, 0, 120, 0, 8, 160, 1, 119, 185, 146, + 160, 56, 1, 0, 60, 160, 1, 3, 120, 0, 15, 160, 1, 0, 29, 6, 160, 1, 80, 72, 84, 84, 80, + 83, 48, 0, 13, 160, 1, 32, 78, 159, 88, 0, 23, 89, 160, 1, 6, 88, 0, 0, 54, 1, 0, 3, 0, + 0, 214, 0, 4, 100, 0, 4, 104, 2, 95, 6, 0, 34, 4, 26, 160, 1, 4, 2, 110, 0, 6, 164, 1, + 2, 81, 0, 10, 112, 2, 32, 187, 184, 120, 0, 8, 112, 2, 6, 120, 0, 4, 108, 0, 4, 66, 1, + 15, 112, 2, 0, 0, 202, 2, 0, 48, 0, 13, 208, 0, 32, 251, 188, 88, 0, 31, 88, 208, 0, + 30, 15, 56, 3, 37, 32, 49, 199, 112, 0, 15, 200, 0, 38, 15, 56, 3, 6, 32, 48, 202, 88, + 0, 8, 56, 3, 6, 32, 1, 15, 152, 1, 9, 15, 56, 3, 37, 74, 213, 153, 166, 56, 56, 3, 0, + 112, 0, 0, 106, 0, 15, 56, 3, 39, 83, 176, 92, 11, 0, 198, 152, 3, 176, 230, 61, 120, + 83, 1, 0, 48, 0, 161, 213, 1, 56, 3, 1, 208, 106, 118, 34, 0, 83, 116, 97, 116, 101, + 51, 115, 241, 3, 73, 110, 116, 101, 114, 102, 97, 99, 101, 47, 101, 110, 48, 47, 73, + 80, 118, 54, 224, 1, 23, 240, 72, 0, 32, 229, 65, 72, 0, 65, 80, 0, 232, 214, 72, 0, + 51, 10, 0, 8, 81, 5, 16, 0, 82, 0, 65, 1, 0, 34, 4, 24, 0, 33, 4, 2, 6, 0, 1, 204, 4, + 17, 4, 170, 3, 33, 4, 5, 12, 0, 16, 6, 142, 52, 33, 4, 25, 220, 0, 2, 154, 52, 0, 87, + 1, 2, 72, 4, 38, 240, 87, 176, 0, 32, 36, 67, 104, 0, 65, 14, 0, 7, 74, 38, 0, 18, 1, + 52, 0, 2, 40, 0, 38, 144, 24, 40, 0, 64, 89, 237, 34, 84, 80, 102, 32, 53, 96, 77, 108, + 6, 50, 110, 0, 184, 0, 8, 40, 0, 63, 112, 25, 35, 40, 0, 18, 47, 7, 45, 40, 0, 7, 8, + 80, 1, 79, 48, 22, 36, 84, 80, 1, 31, 17, 52, 192, 0, 8, 80, 1, 32, 1, 25, 72, 0, 15, + 80, 1, 67, 38, 32, 88, 40, 1, 32, 90, 26, 104, 0, 20, 20, 80, 1, 64, 2, 0, 4, 14, 120, + 1, 3, 86, 1, 2, 88, 1, 8, 224, 0, 64, 40, 190, 170, 84, 184, 8, 8, 48, 2, 28, 26, 48, + 2, 173, 71, 108, 111, 98, 97, 108, 47, 68, 78, 83, 64, 0, 32, 158, 193, 64, 0, 25, 41, + 112, 2, 31, 27, 64, 0, 4, 64, 73, 80, 118, 52, 141, 0, 0, 3, 0, 0, 72, 0, 8, 32, 1, 32, + 190, 196, 72, 0, 23, 87, 32, 1, 3, 25, 9, 1, 112, 2, 0, 110, 3, 10, 106, 2, 81, 7, 0, + 34, 4, 11, 18, 0, 17, 12, 6, 0, 16, 13, 62, 2, 1, 230, 0, 96, 34, 4, 14, 0, 1, 0, 25, + 51, 98, 40, 68, 78, 83, 41, 32, 71, 0, 0, 112, 0, 8, 40, 1, 32, 115, 198, 112, 0, 8, + 40, 1, 1, 201, 9, 1, 66, 0, 1, 9, 0, 86, 0, 2, 2, 128, 82, 40, 8, 161, 203, 94, 250, + 84, 1, 0, 21, 0, 59, 56, 248, 2, 48, 2, 0, 4, 16, 3, 0, 156, 0, 0, 8, 0, 2, 88, 1, 38, + 64, 83, 48, 0, 64, 181, 20, 251, 84, 237, 36, 32, 79, 57, 48, 0, 2, 32, 0, 0, 168, 2, + 4, 120, 8, 63, 202, 51, 255, 128, 2, 6, 38, 32, 6, 72, 0, 162, 5, 9, 19, 85, 1, 0, 52, + 0, 241, 180, 6, 1, 32, 0, 4, 65, 0, 0, 120, 0, 85, 4, 0, 18, 4, 20, 148, 8, 240, 5, + 101, 110, 48, 0, 162, 139, 67, 251, 203, 2, 135, 86, 223, 127, 153, 142, 220, 244, 230, + 175, 153, 0, 0, 248, 0, 8, 120, 0, 32, 216, 12, 80, 0, 15, 72, 3, 4, 7, 192, 0, 32, 42, + 20, 40, 0, 64, 127, 0, 102, 175, 112, 3, 34, 34, 12, 114, 0, 2, 126, 0, 32, 18, 4, 229, + 10, 2, 12, 9, 114, 0, 8, 0, 196, 128, 249, 130, 18, 24, 18, 162, 10, 0, 4, 152, 0, 16, + 20, 6, 8, 1, 100, 6, 48, 34, 4, 36, 70, 0, 33, 4, 37, 6, 0, 49, 38, 0, 1, 176, 0, 255, + 1, 121, 133, 19, 120, 32, 67, 203, 253, 243, 21, 218, 112, 197, 254, 208, 128, 192, 0, + 17, 32, 13, 26, 152, 0, 15, 192, 0, 4, 7, 232, 0, 63, 52, 28, 21, 40, 0, 18, 47, 10, + 136, 40, 0, 19, 63, 229, 6, 24, 40, 0, 18, 47, 45, 15, 40, 0, 19, 47, 127, 21, 40, 0, + 19, 47, 110, 23, 40, 0, 19, 47, 125, 30, 40, 0, 19, 47, 59, 32, 40, 0, 19, 47, 239, 33, + 40, 0, 19, 47, 53, 35, 40, 0, 19, 47, 126, 36, 40, 0, 19, 47, 170, 37, 40, 0, 19, 47, + 213, 38, 40, 0, 19, 47, 79, 42, 40, 0, 19, 47, 223, 44, 40, 0, 19, 47, 89, 46, 40, 0, + 19, 47, 226, 51, 40, 0, 19, 47, 128, 56, 40, 0, 19, 47, 39, 58, 40, 0, 19, 63, 172, 46, + 26, 40, 0, 18, 47, 17, 51, 40, 0, 19, 47, 30, 53, 40, 0, 19, 47, 212, 57, 40, 0, 19, + 63, 226, 6, 28, 40, 0, 6, 38, 192, 54, 192, 3, 49, 42, 48, 37, 40, 0, 33, 204, 64, 74, + 8, 16, 1, 135, 19, 4, 208, 4, 23, 224, 40, 0, 160, 189, 60, 157, 85, 1, 0, 182, 0, 245, + 65, 40, 0, 34, 34, 3, 152, 5, 2, 46, 0, 0, 20, 42, 240, 21, 156, 0, 105, 100, 58, 32, + 49, 44, 32, 116, 121, 112, 101, 58, 32, 68, 111, 53, 51, 44, 32, 115, 111, 117, 114, + 99, 101, 58, 32, 115, 99, 44, 32, 115, 99, 111, 25, 0, 116, 110, 111, 110, 101, 44, 32, + 105, 25, 9, 32, 58, 32, 26, 9, 50, 52, 44, 32, 204, 65, 80, 115, 58, 32, 123, 60, 191, + 6, 241, 2, 58, 66, 66, 71, 73, 100, 109, 119, 69, 62, 58, 53, 51, 125, 44, 32, 100, 23, + 15, 0, 31, 0, 208, 46, 125, 44, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 17, 0, + 87, 97, 45, 111, 107, 125, 83, 0, 48, 32, 112, 114, 218, 16, 33, 116, 105, 30, 0, 95, + 105, 112, 118, 52, 125, 208, 0, 0, 32, 19, 115, 208, 0, 23, 187, 208, 0, 1, 8, 7, 5, + 208, 0, 17, 161, 208, 0, 31, 50, 208, 0, 14, 5, 202, 0, 7, 130, 0, 15, 213, 0, 86, 3, + 216, 0, 8, 120, 6, 32, 77, 172, 216, 0, 15, 184, 5, 15, 47, 118, 176, 40, 0, 19, 47, + 184, 181, 40, 0, 3, 4, 16, 16, 19, 248, 80, 31, 0, 61, 1, 8, 3, 0, 28, 232, 16, 16, + 129, 16, 8, 0, 81, 25, 3, 0, 3, 255, 7, 241, 2, 0, 0, 143, 28, 27, 49, 1, 0, 198, 0, + 233, 129, 54, 3, 128, 255, 2, 208, 28, 17, 14, 84, 8, 81, 11, 0, 2, 4, 152, 124, 7, 66, + 25, 0, 141, 0, 147, 17, 33, 32, 80, 12, 48, 8, 83, 14, 0, 111, 93, 49, 40, 49, 41, 157, + 145, 236, 45, 119, 114, 105, 116, 101, 45, 99, 114, 101, 97, 116, 101, 32, 199, 17, + 103, 67, 97, 99, 104, 101, 115, 162, 17, 98, 107, 101, 120, 116, 46, 99, 22, 0, 188, + 68, 105, 114, 101, 99, 116, 111, 114, 105, 101, 115, 56, 0, 7, 88, 129, 85, 75, 101, + 120, 116, 73, 22, 100, 18, 115, 197, 17, 160, 46, 103, 122, 46, 71, 52, 116, 104, 77, + 89, 136, 1, 11, 224, 0, 127, 59, 83, 61, 49, 1, 0, 148, 224, 0, 12, 31, 91, 224, 0, 90, + 3, 8, 150, 1, 129, 1, 12, 176, 0, 127, 76, 104, 138, 49, 1, 0, 172, 176, 0, 12, 31, + 115, 176, 0, 90, 11, 200, 1, 17, 68, 188, 141, 6, 150, 1, 0, 199, 0, 13, 200, 0, 63, + 18, 224, 140, 120, 1, 139, 101, 0, 8, 0, 16, 25, 3, 48, 38, 162, 185, 98, 136, 77, 1, + 0, 135, 0, 228, 125, 8, 3, 32, 2, 4, 232, 10, 0, 6, 10, 2, 252, 13, 143, 11, 0, 34, 4, + 12, 0, 91, 0, 251, 2, 76, 5, 27, 2, 34, 4, 0, 200, 2, 4, 160, 0, 32, 169, 107, 160, 0, + 25, 101, 24, 2, 160, 8, 0, 34, 4, 8, 0, 5, 0, 2, 4, 166, 39, 224, 34, 4, 13, 0, 56, 0, + 83, 97, 110, 100, 98, 111, 120, 0, 204, 38, 250, 5, 0, 97, 108, 108, 111, 119, 32, 105, + 112, 99, 45, 112, 111, 115, 105, 120, 45, 115, 104, 109, 163, 3, 6, 140, 3, 0, 48, 0, + 112, 46, 98, 117, 100, 103, 101, 116, 75, 12, 13, 128, 0, 64, 116, 16, 2, 78, 32, 1, 8, + 40, 4, 14, 128, 0, 31, 90, 128, 0, 1, 160, 102, 105, 108, 101, 45, 114, 101, 97, 100, + 45, 113, 24, 35, 32, 47, 53, 21, 211, 47, 118, 97, 114, 47, 100, 98, 47, 68, 117, 101, + 116, 65, 10, 57, 20, 83, 122, 56, 15, 22, 0, 3, 144, 67, 108, 97, 115, 115, 67, 46, + 100, 98, 112, 5, 10, 192, 1, 127, 231, 215, 17, 78, 1, 0, 128, 192, 1, 6, 0, 136, 17, + 72, 6, 0, 90, 0, 25, 1, 15, 153, 0, 65, 12, 56, 1, 32, 45, 224, 152, 0, 31, 136, 184, + 1, 12, 31, 91, 56, 1, 6, 2, 175, 1, 15, 57, 1, 55, 12, 160, 0, 127, 132, 135, 24, 78, + 1, 0, 139, 160, 0, 12, 31, 94, 160, 0, 6, 15, 216, 1, 59, 48, 45, 119, 97, 77, 93, 0, + 200, 5, 11, 168, 0, 127, 58, 6, 25, 78, 1, 0, 140, 168, 0, 12, 31, 95, 168, 0, 6, 15, + 72, 1, 60, 5, 169, 0, 12, 80, 1, 63, 210, 5, 27, 80, 1, 121, 48, 115, 104, 109, 158, 5, + 14, 80, 1, 32, 112, 54, 168, 0, 15, 80, 1, 119, 4, 169, 0, 12, 80, 1, 63, 25, 19, 140, + 120, 4, 126, 0, 64, 9, 4, 152, 5, 32, 201, 81, 160, 0, 15, 224, 3, 135, 63, 108, 197, + 147, 144, 2, 121, 4, 55, 3, 13, 144, 2, 63, 14, 150, 148, 144, 2, 122, 4, 169, 0, 12, + 168, 0, 63, 76, 12, 150, 80, 1, 121, 4, 55, 3, 13, 80, 1, 32, 218, 70, 168, 0, 15, 224, + 3, 131, 80, 206, 233, 22, 0, 248, 95, 9, 224, 0, 0, 0, 45, 253, 240, 78, 1, 0, 121, 0, + 95, 95, 62, 120, 9, 16, 11, 114, 9, 80, 9, 0, 2, 4, 158, 228, 143, 131, 4, 9, 0, 6, 0, + 2, 8, 5, 172, 12, 32, 2, 8, 0, 20, 0, 3, 0, 8, 10, 0, 19, 243, 138, 3, 21, 2, 178, 23, + 53, 2, 8, 226, 50, 0, 16, 241, 47, 0, 1, 50, 0, 16, 201, 55, 73, 243, 2, 0, 0, 0, 116, + 120, 95, 102, 108, 117, 115, 104, 0, 100, 105, 115, 107, 49, 31, 0, 13, 64, 1, 127, + 203, 75, 68, 79, 1, 0, 84, 64, 1, 12, 31, 39, 112, 6, 1, 1, 71, 159, 86, 45, 103, 101, + 116, 45, 2, 15, 33, 32, 115, 68, 11, 16, 45, 150, 15, 1, 115, 0, 4, 48, 11, 19, 55, + 190, 0, 127, 128, 195, 144, 80, 1, 0, 85, 112, 0, 0, 64, 10, 0, 2, 4, 50, 28, 85, 34, + 4, 18, 0, 35, 112, 0, 5, 202, 39, 5, 129, 13, 183, 109, 97, 99, 104, 45, 108, 111, 111, + 107, 117, 112, 216, 9, 48, 116, 99, 99, 61, 0, 5, 160, 11, 4, 112, 0, 64, 90, 233, 150, + 80, 168, 84, 14, 208, 9, 8, 112, 0, 31, 42, 112, 0, 34, 18, 46, 237, 0, 0, 231, 0, 13, + 120, 0, 79, 170, 15, 193, 81, 232, 0, 89, 79, 44, 254, 197, 81, 232, 0, 82, 101, 0, 2, + 0, 101, 11, 157, 120, 161, 176, 99, 98, 76, 88, 1, 0, 6, 0, 241, 29, 118, 7, 1, 0, 16, + 23, 54, 0, 192, 14, 32, 0, 32, 76, 114, 32, 0, 113, 72, 0, 99, 56, 118, 0, 2, 182, 26, + 29, 60, 248, 32, 14, 78, 146, 2, 138, 13, 2, 24, 0, 6, 129, 13, 53, 46, 107, 99, 24, + 32, 4, 248, 110, 12, 24, 32, 28, 160, 8, 16, 116, 0, 4, 2, 16, 189, 98, 4, 224, 30, 32, + 80, 222, 96, 16, 240, 3, 187, 0, 115, 213, 3, 4, 25, 0, 34, 6, 34, 4, 0, 0, 24, 0, 18, + 4, 103, 32, 49, 50, 4, 24, 6, 32, 240, 14, 40, 0, 7, 0, 64, 4, 47, 0, 36, 0, 64, 4, 83, + 0, 60, 0, 110, 119, 95, 112, 97, 116, 104, 95, 101, 118, 97, 108, 117, 58, 93, 240, 16, + 95, 115, 116, 97, 114, 116, 0, 23, 170, 19, 1, 115, 6, 71, 135, 129, 142, 56, 14, 51, + 9, 242, 1, 60, 78, 85, 76, 76, 62, 0, 103, 150, 71, 44, 105, 99, 161, 17, 0, 16, 0, + 245, 13, 100, 101, 102, 105, 110, 105, 116, 101, 0, 115, 97, 116, 105, 115, 102, 105, + 101, 100, 32, 40, 80, 97, 116, 104, 32, 105, 115, 32, 19, 0, 16, 41, 42, 0, 8, 176, 18, + 3, 205, 18, 48, 100, 44, 32, 94, 18, 2, 241, 0, 12, 0, 24, 32, 76, 253, 216, 0, 15, + 136, 17, 15, 63, 244, 0, 158, 40, 0, 18, 47, 246, 2, 40, 0, 19, 47, 173, 4, 40, 0, 19, + 47, 251, 8, 40, 0, 19, 47, 146, 10, 40, 0, 19, 63, 118, 201, 165, 40, 0, 18, 47, 82, + 255, 40, 0, 19, 63, 121, 4, 166, 40, 0, 18, 47, 83, 6, 40, 0, 19, 47, 203, 9, 40, 0, + 19, 63, 26, 151, 168, 40, 0, 18, 47, 152, 246, 40, 0, 7, 38, 160, 39, 96, 21, 161, 253, + 83, 215, 85, 1, 0, 34, 0, 27, 203, 176, 29, 48, 3, 0, 4, 102, 79, 49, 0, 4, 77, 178, + 29, 0, 15, 54, 2, 163, 144, 1, 45, 5, 1, 128, 12, 70, 2, 2, 64, 41, 64, 0, 161, 135, + 66, 218, 85, 1, 0, 78, 0, 233, 239, 64, 0, 64, 7, 0, 4, 10, 42, 0, 92, 4, 0, 208, 0, + 64, 154, 33, 0, 59, 26, 2, 88, 0, 247, 8, 20, 0, 8, 0, 140, 185, 235, 52, 27, 235, 87, + 202, 114, 128, 167, 133, 1, 216, 15, 190, 80, 84, 82, 108, 0, 102, 4, 0, 2, 2, 240, 56, + 104, 0, 161, 34, 30, 3, 86, 1, 0, 220, 0, 117, 76, 224, 21, 20, 6, 104, 0, 32, 49, 130, + 144, 33, 17, 30, 148, 35, 4, 192, 32, 240, 9, 4, 0, 64, 4, 20, 0, 156, 0, 73, 130, 39, + 198, 79, 29, 157, 214, 86, 50, 80, 105, 156, 103, 163, 36, 98, 0, 15, 6, 22, 139, 0, + 96, 1, 10, 128, 4, 127, 117, 81, 5, 86, 1, 0, 190, 128, 4, 12, 223, 21, 0, 64, 4, 61, + 0, 20, 0, 64, 4, 81, 0, 65, 128, 4, 6, 240, 1, 96, 32, 195, 18, 36, 18, 66, 185, 166, + 178, 153, 28, 97, 176, 220, 187, 201, 22, 208, 35, 49, 100, 100, 55, 102, 52, 56, 98, + 58, 53, 51, 64, 141, 27, 7, 142, 4, 15, 126, 4, 49, 34, 44, 32, 205, 146, 0, 208, 1, + 38, 48, 68, 216, 35, 32, 154, 152, 216, 0, 80, 37, 0, 87, 206, 6, 64, 53, 1, 136, 39, + 0, 76, 5, 80, 16, 0, 1, 0, 60, 153, 0, 6, 98, 23, 0, 80, 2, 0, 40, 6, 54, 2, 160, 72, + 64, 0, 176, 85, 91, 17, 86, 1, 0, 131, 0, 105, 7, 7, 64, 0, 16, 9, 152, 5, 80, 10, 0, + 0, 8, 46, 45, 0, 0, 4, 0, 1, 168, 18, 49, 64, 4, 10, 20, 2, 49, 26, 0, 4, 60, 57, 81, + 6, 0, 18, 4, 12, 186, 5, 253, 4, 36, 0, 12, 0, 64, 4, 48, 0, 17, 0, 91, 81, 51, 51, 51, + 50, 57, 93, 32, 120, 0, 48, 85, 68, 80, 160, 28, 112, 47, 52, 0, 185, 115, 1, 0, 127, + 24, 0, 89, 0, 244, 0, 66, 66, 66, 86, 65, 68, 82, 98, 32, 73, 78, 32, 80, 84, 82, 96, + 61, 86, 0, 2, 2, 112, 74, 160, 0, 168, 206, 130, 49, 87, 1, 0, 132, 0, 110, 20, 160, 0, + 48, 34, 4, 10, 71, 0, 5, 166, 0, 49, 64, 4, 11, 160, 0, 17, 27, 160, 0, 23, 31, 160, 0, + 17, 37, 160, 0, 25, 49, 160, 0, 15, 161, 0, 10, 16, 132, 124, 33, 0, 160, 0, 15, 161, + 0, 3, 0, 64, 1, 38, 32, 58, 32, 34, 161, 226, 252, 51, 87, 1, 0, 36, 0, 232, 84, 80, 3, + 18, 2, 74, 3, 2, 134, 1, 5, 65, 0, 96, 80, 84, 82, 32, 73, 78, 84, 0, 1, 128, 1, 38, + 112, 53, 64, 0, 161, 125, 85, 57, 87, 1, 0, 134, 0, 162, 28, 64, 0, 24, 11, 144, 3, 0, + 140, 1, 21, 12, 150, 3, 17, 12, 226, 0, 17, 28, 226, 0, 16, 32, 19, 4, 0, 185, 30, 1, + 140, 162, 0, 188, 31, 17, 43, 240, 34, 255, 0, 44, 0, 16, 0, 81, 117, 101, 114, 121, + 82, 101, 99, 111, 114, 100, 186, 3, 2, 53, 65, 68, 68, 136, 38, 240, 1, 109, 177, 159, + 5, 175, 223, 170, 152, 88, 130, 86, 65, 151, 40, 39, 155, 56, 3, 70, 2, 2, 208, 30, 48, + 4, 64, 255, 89, 61, 87, 216, 4, 32, 35, 63, 24, 1, 15, 216, 4, 19, 38, 0, 29, 64, 0, + 32, 130, 98, 64, 0, 65, 84, 0, 58, 1, 112, 32, 20, 8, 224, 0, 6, 216, 4, 14, 118, 4, 4, + 54, 5, 0, 222, 4, 15, 124, 4, 1, 6, 222, 4, 2, 176, 0, 0, 232, 38, 17, 33, 14, 1, 151, + 0, 0, 188, 57, 129, 92, 1, 0, 90, 232, 38, 1, 151, 11, 0, 72, 5, 16, 192, 53, 1, 0, + 210, 2, 0, 17, 0, 10, 232, 38, 3, 21, 18, 1, 90, 39, 17, 6, 244, 155, 244, 8, 1, 0, + 160, 28, 35, 169, 146, 51, 93, 88, 233, 169, 240, 87, 172, 165, 237, 112, 0, 116, 105, + 109, 101, 191, 5, 1, 120, 0, 38, 112, 57, 120, 0, 32, 138, 97, 120, 0, 23, 69, 88, 5, + 2, 120, 0, 32, 155, 207, 88, 5, 0, 230, 8, 6, 114, 0, 38, 5, 0, 254, 35, 241, 1, 154, + 211, 61, 159, 183, 85, 188, 107, 112, 136, 252, 39, 61, 239, 144, 45, 236, 40, 1, 165, + 0, 85, 2, 2, 96, 239, 10, 96, 0, 32, 75, 104, 96, 0, 65, 88, 0, 245, 178, 136, 1, 31, + 5, 90, 0, 5, 95, 34, 4, 21, 0, 29, 86, 0, 3, 32, 32, 40, 93, 0, 33, 32, 114, 27, 2, + 224, 115, 32, 97, 114, 101, 32, 117, 110, 117, 115, 97, 98, 108, 101, 200, 89, 10, 208, + 0, 32, 186, 115, 112, 0, 14, 208, 0, 47, 51, 255, 208, 0, 28, 3, 42, 38, 0, 48, 1, 8, + 168, 1, 119, 86, 191, 131, 92, 1, 0, 89, 168, 1, 0, 80, 4, 15, 168, 1, 13, 16, 106, 36, + 0, 1, 250, 6, 17, 17, 50, 42, 245, 9, 22, 0, 1, 0, 65, 93, 244, 132, 236, 231, 228, + 101, 119, 206, 188, 102, 237, 30, 253, 78, 0, 97, 112, 115, 167, 1, 1, 216, 0, 8, 144, + 40, 74, 70, 116, 132, 92, 248, 38, 15, 168, 1, 9, 15, 72, 1, 2, 0, 48, 0, 1, 88, 0, 8, + 48, 42, 32, 33, 133, 88, 0, 8, 192, 39, 6, 88, 0, 0, 200, 3, 2, 3, 0, 6, 60, 1, 4, 144, + 40, 0, 56, 22, 19, 25, 144, 40, 15, 110, 0, 2, 3, 143, 40, 0, 112, 0, 8, 160, 1, 59, + 13, 52, 134, 160, 1, 2, 64, 1, 32, 141, 27, 100, 0, 31, 26, 112, 2, 6, 240, 1, 232, + 190, 126, 210, 132, 127, 186, 74, 158, 38, 198, 221, 98, 126, 210, 171, 19, 2, 1, 57, + 0, 11, 112, 2, 32, 156, 58, 96, 0, 8, 112, 2, 15, 90, 0, 3, 2, 112, 2, 15, 86, 0, 2, + 15, 112, 2, 26, 32, 119, 70, 112, 0, 8, 112, 2, 2, 208, 0, 47, 25, 109, 208, 0, 28, 15, + 112, 2, 4, 74, 139, 213, 135, 92, 0, 43, 17, 13, 96, 0, 15, 24, 4, 11, 16, 152, 36, 0, + 3, 112, 2, 0, 162, 25, 15, 0, 43, 19, 8, 96, 7, 64, 78, 189, 136, 92, 16, 143, 12, 96, + 7, 19, 32, 90, 0, 2, 96, 31, 15, 96, 7, 15, 159, 15, 0, 91, 81, 54, 53, 51, 51, 49, 96, + 7, 10, 40, 108, 103, 96, 7, 179, 102, 80, 121, 111, 99, 109, 32, 73, 78, 32, 65, 94, 7, + 0, 133, 2, 10, 208, 42, 59, 253, 148, 137, 16, 3, 2, 120, 1, 15, 238, 1, 3, 15, 232, 1, + 2, 0, 48, 0, 1, 88, 0, 8, 16, 3, 32, 5, 159, 88, 0, 8, 16, 3, 6, 88, 0, 10, 16, 3, 2, + 172, 2, 15, 16, 3, 1, 15, 110, 0, 2, 15, 16, 3, 4, 59, 221, 93, 139, 64, 2, 2, 224, 1, + 32, 177, 192, 64, 2, 17, 24, 100, 0, 4, 216, 10, 8, 128, 5, 15, 108, 46, 2, 15, 16, 3, + 0, 32, 157, 100, 96, 0, 8, 16, 3, 15, 90, 0, 3, 2, 16, 3, 15, 86, 0, 2, 15, 16, 3, 26, + 32, 206, 114, 112, 0, 8, 16, 3, 2, 208, 0, 47, 22, 86, 208, 0, 28, 3, 16, 3, 4, 200, + 31, 31, 200, 192, 15, 4, 32, 184, 15, 93, 38, 19, 0, 214, 8, 2, 0, 1, 8, 200, 2, 63, + 112, 198, 140, 200, 2, 2, 16, 42, 150, 0, 0, 4, 0, 15, 200, 2, 24, 63, 50, 55, 57, 40, + 10, 12, 40, 17, 204, 200, 2, 110, 72, 83, 105, 89, 84, 106, 200, 2, 8, 80, 6, 59, 155, + 107, 141, 80, 6, 2, 168, 41, 15, 224, 3, 11, 15, 80, 6, 1, 255, 1, 154, 28, 234, 187, + 201, 157, 84, 209, 1, 158, 222, 225, 79, 90, 33, 240, 80, 6, 11, 32, 152, 178, 120, 0, + 8, 80, 6, 2, 168, 1, 15, 30, 2, 3, 15, 24, 2, 2, 0, 48, 0, 1, 112, 1, 8, 64, 3, 32, + 143, 186, 88, 0, 8, 64, 3, 6, 88, 0, 10, 64, 3, 2, 220, 2, 15, 64, 3, 1, 15, 110, 0, 2, + 15, 64, 3, 4, 59, 211, 64, 142, 112, 2, 2, 64, 1, 32, 124, 150, 112, 2, 17, 34, 100, 0, + 15, 64, 3, 1, 255, 1, 21, 41, 9, 135, 240, 82, 184, 234, 194, 110, 86, 219, 141, 208, + 52, 103, 80, 6, 5, 32, 160, 69, 96, 0, 8, 64, 3, 15, 90, 0, 3, 2, 64, 3, 15, 86, 0, 2, + 15, 64, 3, 26, 32, 72, 79, 112, 0, 8, 64, 3, 2, 208, 0, 47, 13, 66, 208, 0, 28, 3, 64, + 3, 0, 160, 1, 8, 72, 8, 59, 73, 26, 144, 248, 1, 2, 96, 0, 15, 214, 0, 3, 15, 208, 0, + 2, 0, 48, 0, 13, 248, 1, 32, 96, 34, 88, 0, 8, 248, 1, 6, 88, 0, 10, 248, 1, 2, 148, 1, + 15, 248, 1, 1, 15, 110, 0, 2, 7, 248, 1, 8, 216, 3, 63, 0, 203, 149, 216, 3, 2, 16, 40, + 118, 0, 0, 4, 0, 15, 216, 3, 25, 79, 50, 48, 51, 56, 160, 6, 10, 40, 229, 51, 216, 3, + 110, 100, 86, 112, 107, 103, 81, 216, 3, 8, 160, 0, 63, 154, 239, 151, 160, 0, 2, 16, + 50, 156, 0, 0, 4, 0, 15, 160, 0, 24, 79, 49, 54, 57, 48, 160, 14, 11, 40, 88, 232, 160, + 0, 111, 113, 107, 67, 113, 117, 112, 160, 0, 0, 7, 248, 17, 119, 4, 21, 163, 92, 1, 0, + 32, 248, 17, 1, 97, 5, 16, 4, 82, 12, 0, 176, 1, 19, 6, 55, 12, 12, 240, 17, 119, 142, + 203, 166, 92, 1, 0, 77, 240, 17, 0, 127, 5, 80, 0, 4, 0, 80, 1, 125, 5, 1, 220, 1, 7, + 112, 3, 3, 80, 0, 61, 21, 0, 6, 152, 12, 1, 162, 2, 5, 156, 12, 1, 104, 0, 37, 237, 10, + 128, 13, 160, 49, 76, 170, 92, 1, 0, 63, 0, 152, 239, 217, 0, 96, 34, 5, 0, 4, 154, 93, + 158, 72, 64, 224, 58, 129, 253, 102, 44, 2, 130, 21, 8, 156, 12, 13, 134, 10, 0, 96, 0, + 1, 168, 2, 0, 128, 10, 4, 88, 0, 32, 133, 90, 88, 0, 8, 96, 3, 2, 192, 0, 0, 94, 0, 14, + 84, 0, 15, 240, 12, 8, 1, 94, 0, 0, 243, 0, 70, 2, 2, 80, 238, 184, 0, 32, 131, 97, 96, + 0, 65, 65, 0, 7, 247, 184, 0, 33, 6, 0, 84, 0, 3, 190, 0, 15, 134, 12, 4, 15, 186, 0, + 3, 0, 151, 0, 2, 96, 0, 8, 88, 16, 127, 76, 44, 209, 92, 1, 0, 236, 88, 16, 4, 17, 148, + 52, 0, 15, 88, 16, 17, 23, 121, 152, 9, 15, 88, 16, 8, 80, 108, 103, 129, 128, 0, 176, + 23, 1, 249, 16, 8, 153, 9, 48, 44, 32, 53, 98, 2, 227, 67, 78, 65, 77, 69, 32, 66, 66, + 84, 103, 104, 68, 85, 88, 21, 0, 167, 65, 32, 66, 66, 89, 102, 121, 110, 67, 102, 17, + 0, 103, 107, 108, 110, 113, 117, 80, 17, 0, 103, 81, 117, 80, 104, 102, 103, 17, 0, + 103, 68, 103, 106, 104, 66, 77, 17, 0, 80, 66, 101, 105, 79, 104, 66, 2, 14, 8, 1, 143, + 75, 167, 211, 92, 1, 0, 31, 1, 96, 17, 3, 31, 217, 8, 1, 22, 23, 172, 0, 4, 15, 8, 1, + 8, 33, 229, 51, 8, 1, 1, 28, 21, 10, 1, 4, 3, 175, 0, 4, 8, 1, 99, 117, 102, 77, 77, + 68, 108, 21, 0, 0, 8, 1, 103, 74, 120, 85, 118, 71, 97, 17, 0, 103, 113, 111, 99, 86, + 120, 76, 17, 0, 103, 118, 86, 82, 66, 73, 81, 17, 0, 103, 102, 65, 76, 72, 113, 83, 17, + 0, 103, 70, 113, 83, 72, 86, 116, 17, 0, 103, 74, 90, 111, 88, 75, 114, 17, 0, 103, 82, + 113, 81, 79, 68, 101, 17, 0, 98, 101, 103, 117, 104, 100, 73, 56, 1, 8, 248, 17, 64, + 127, 65, 212, 92, 24, 17, 6, 248, 17, 32, 51, 255, 48, 2, 54, 0, 0, 14, 225, 1, 20, 65, + 246, 17, 2, 64, 0, 53, 96, 252, 10, 248, 17, 64, 2, 41, 213, 92, 128, 51, 33, 184, 236, + 208, 48, 19, 1, 240, 21, 1, 40, 0, 38, 176, 235, 40, 0, 32, 234, 141, 40, 0, 65, 97, 0, + 184, 171, 248, 15, 5, 88, 14, 0, 110, 0, 95, 0, 8, 0, 230, 128, 198, 3, 4, 2, 236, 16, + 94, 242, 4, 21, 0, 16, 14, 16, 0, 116, 3, 244, 0, 244, 124, 34, 126, 126, 231, 99, 195, + 112, 232, 231, 148, 105, 177, 64, 249, 9, 0, 128, 0, 0, 232, 3, 4, 224, 18, 32, 29, + 217, 128, 0, 8, 232, 3, 2, 128, 0, 32, 226, 32, 130, 3, 2, 124, 8, 7, 168, 4, 5, 232, + 3, 241, 1, 69, 240, 155, 141, 96, 156, 255, 116, 231, 122, 144, 170, 79, 18, 202, 91, + 166, 4, 0, 175, 5, 0, 96, 0, 7, 0, 19, 32, 138, 230, 96, 0, 23, 137, 0, 19, 2, 232, 3, + 0, 224, 0, 0, 64, 5, 0, 0, 19, 0, 18, 0, 6, 0, 19, 0, 50, 15, 16, 33, 223, 0, 1, 226, + 0, 145, 34, 4, 37, 0, 9, 0, 34, 4, 46, 0, 19, 27, 47, 0, 19, 15, 18, 4, 2, 0, 1, 19, + 35, 105, 109, 16, 7, 15, 8, 1, 9, 8, 136, 1, 59, 78, 31, 214, 136, 1, 0, 150, 0, 2, + 138, 4, 15, 78, 5, 9, 0, 169, 0, 15, 136, 1, 49, 59, 158, 238, 215, 136, 1, 2, 128, 0, + 47, 187, 43, 136, 1, 39, 0, 112, 5, 4, 232, 1, 32, 244, 244, 96, 0, 14, 112, 5, 0, 96, + 0, 15, 238, 1, 5, 15, 228, 1, 5, 1, 153, 0, 0, 240, 17, 7, 48, 3, 59, 30, 3, 217, 48, + 3, 0, 202, 12, 4, 48, 3, 3, 9, 4, 15, 48, 3, 8, 32, 51, 126, 64, 0, 8, 48, 3, 2, 172, + 31, 0, 176, 2, 8, 168, 1, 32, 138, 151, 40, 0, 8, 48, 3, 2, 56, 11, 0, 110, 0, 98, 0, + 8, 0, 142, 0, 252, 246, 6, 13, 186, 2, 7, 168, 1, 13, 56, 11, 0, 188, 2, 240, 1, 12, + 48, 188, 89, 187, 47, 4, 211, 88, 208, 126, 61, 190, 62, 80, 173, 47, 0, 3, 232, 0, 8, + 48, 3, 32, 196, 219, 128, 0, 8, 48, 3, 2, 128, 0, 32, 80, 148, 168, 1, 28, 37, 118, 0, + 5, 48, 3, 248, 1, 221, 231, 22, 225, 9, 110, 17, 136, 54, 78, 49, 113, 212, 215, 197, + 92, 48, 3, 53, 128, 14, 11, 24, 7, 161, 169, 57, 222, 92, 1, 0, 107, 0, 183, 201, 30, + 56, 20, 9, 16, 4, 0, 162, 1, 0, 48, 3, 2, 3, 0, 0, 108, 0, 2, 226, 0, 0, 32, 10, 17, + 18, 102, 52, 2, 64, 52, 0, 48, 22, 17, 9, 102, 61, 12, 190, 1, 246, 1, 57, 75, 146, + 167, 126, 47, 132, 66, 107, 101, 160, 213, 184, 230, 187, 14, 35, 3, 1, 193, 0, 11, + 136, 0, 47, 230, 151, 136, 0, 69, 255, 1, 170, 204, 56, 166, 114, 216, 33, 118, 136, + 72, 18, 233, 136, 222, 244, 188, 136, 0, 11, 47, 32, 164, 136, 0, 69, 255, 1, 128, 206, + 159, 53, 68, 144, 23, 14, 117, 115, 154, 113, 236, 195, 167, 105, 136, 0, 12, 31, 174, + 136, 0, 69, 250, 1, 38, 73, 55, 172, 143, 142, 151, 246, 29, 194, 49, 244, 136, 129, + 223, 43, 136, 0, 4, 216, 15, 17, 8, 15, 4, 14, 152, 31, 31, 248, 216, 15, 0, 8, 80, 2, + 47, 232, 182, 184, 0, 69, 250, 1, 114, 26, 162, 118, 39, 174, 132, 190, 212, 126, 198, + 249, 247, 81, 75, 91, 184, 0, 0, 184, 3, 0, 8, 25, 17, 94, 120, 3, 95, 0, 0, 102, 217, + 223, 8, 6, 2, 0, 128, 4, 0, 216, 2, 0, 8, 6, 2, 210, 2, 15, 8, 6, 33, 12, 236, 2, 1, + 94, 3, 10, 8, 6, 243, 1, 109, 231, 228, 239, 215, 227, 244, 10, 177, 135, 108, 13, 141, + 6, 91, 29, 72, 1, 12, 168, 0, 47, 128, 229, 168, 0, 108, 242, 1, 80, 170, 82, 23, 24, + 5, 224, 245, 141, 92, 251, 157, 52, 146, 98, 145, 167, 0, 1, 56, 8, 8, 80, 1, 47, 123, + 237, 168, 0, 108, 240, 0, 244, 61, 97, 184, 13, 50, 254, 107, 179, 29, 254, 22, 35, + 237, 5, 228, 25, 0, 170, 0, 12, 168, 0, 47, 14, 245, 168, 0, 108, 240, 1, 114, 117, + 114, 56, 107, 163, 53, 56, 115, 203, 96, 152, 253, 92, 68, 151, 165, 0, 15, 168, 0, 0, + 47, 103, 252, 168, 0, 108, 242, 1, 53, 200, 14, 202, 166, 220, 155, 232, 89, 64, 145, + 166, 228, 227, 187, 246, 167, 0, 1, 248, 1, 8, 208, 3, 59, 167, 7, 224, 208, 3, 6, 128, + 6, 18, 34, 29, 6, 1, 114, 3, 4, 140, 6, 15, 32, 6, 7, 12, 146, 6, 254, 1, 81, 120, 189, + 236, 53, 94, 210, 142, 179, 14, 169, 197, 218, 95, 179, 72, 208, 3, 8, 136, 0, 47, 213, + 84, 136, 0, 69, 255, 1, 178, 86, 2, 144, 68, 72, 38, 29, 145, 243, 132, 154, 7, 199, + 183, 215, 136, 0, 11, 47, 31, 95, 136, 0, 69, 255, 1, 45, 9, 2, 7, 68, 61, 96, 222, 66, + 141, 246, 37, 45, 230, 129, 229, 136, 0, 11, 47, 40, 104, 136, 0, 69, 255, 1, 118, 205, + 197, 62, 159, 45, 188, 228, 114, 142, 225, 8, 75, 238, 241, 23, 136, 0, 11, 47, 132, + 112, 136, 0, 69, 255, 1, 11, 212, 225, 14, 194, 243, 102, 64, 168, 247, 35, 253, 29, + 78, 224, 162, 136, 0, 11, 47, 0, 122, 136, 0, 69, 255, 1, 108, 27, 230, 236, 248, 121, + 119, 209, 90, 151, 192, 102, 213, 114, 14, 203, 136, 0, 11, 47, 124, 130, 136, 0, 69, + 255, 1, 182, 36, 126, 184, 205, 126, 219, 152, 219, 69, 195, 140, 139, 235, 127, 143, + 136, 0, 11, 47, 58, 139, 136, 0, 69, 254, 1, 177, 138, 80, 164, 43, 90, 78, 47, 50, 9, + 161, 42, 56, 32, 38, 234, 136, 0, 8, 176, 31, 119, 157, 52, 227, 92, 1, 0, 83, 176, 31, + 1, 89, 8, 7, 152, 18, 14, 230, 68, 8, 158, 18, 15, 106, 7, 2, 5, 158, 18, 2, 88, 5, 83, + 176, 17, 11, 0, 132, 66, 43, 119, 178, 163, 13, 93, 1, 0, 65, 248, 70, 17, 11, 112, 27, + 0, 246, 17, 4, 248, 70, 2, 186, 16, 2, 134, 27, 45, 6, 0, 1, 19, 7, 94, 0, 14, 96, 0, + 74, 172, 90, 16, 93, 32, 68, 0, 16, 5, 10, 96, 0, 10, 230, 27, 13, 225, 27, 7, 146, 53, + 2, 96, 0, 0, 72, 18, 4, 192, 0, 127, 9, 87, 75, 93, 1, 0, 223, 72, 18, 4, 19, 180, 90, + 0, 15, 72, 18, 15, 16, 108, 64, 17, 3, 24, 25, 15, 64, 17, 8, 33, 17, 204, 64, 17, 1, + 125, 0, 10, 25, 25, 3, 180, 16, 4, 64, 17, 107, 100, 81, 101, 100, 82, 121, 21, 0, 99, + 104, 75, 65, 85, 112, 67, 21, 0, 0, 85, 17, 103, 113, 102, 113, 117, 104, 112, 17, 0, + 103, 116, 74, 90, 117, 104, 100, 17, 0, 98, 103, 77, 71, 107, 85, 104, 248, 0, 8, 0, + 17, 74, 239, 210, 77, 93, 0, 17, 0, 170, 29, 4, 208, 13, 3, 153, 0, 11, 208, 13, 8, + 168, 13, 74, 5, 100, 78, 93, 168, 13, 2, 32, 28, 0, 70, 0, 0, 59, 55, 4, 158, 20, 2, + 30, 28, 7, 98, 16, 1, 190, 6, 2, 80, 15, 13, 32, 28, 0, 214, 9, 240, 1, 25, 14, 154, + 40, 87, 32, 126, 213, 186, 64, 132, 30, 78, 251, 237, 242, 47, 0, 4, 208, 7, 7, 168, + 13, 32, 54, 247, 128, 0, 8, 168, 13, 2, 128, 0, 32, 157, 160, 60, 13, 2, 28, 7, 7, 118, + 0, 5, 168, 13, 241, 1, 241, 99, 155, 234, 171, 224, 172, 228, 230, 123, 223, 231, 244, + 39, 250, 245, 74, 10, 3, 96, 0, 0, 224, 0, 4, 208, 10, 63, 2, 146, 80, 224, 0, 2, 0, + 96, 0, 8, 224, 0, 13, 106, 0, 16, 4, 106, 0, 2, 224, 0, 15, 108, 0, 2, 243, 0, 109, 62, + 148, 17, 87, 21, 72, 139, 169, 25, 159, 77, 65, 136, 229, 111, 0, 1, 160, 1, 0, 136, + 14, 4, 128, 0, 32, 6, 163, 128, 0, 14, 224, 0, 32, 234, 76, 224, 0, 0, 213, 15, 8, 244, + 21, 6, 160, 21, 248, 1, 187, 19, 161, 161, 160, 59, 212, 50, 189, 22, 71, 221, 208, 37, + 60, 246, 224, 0, 8, 224, 7, 32, 185, 172, 96, 0, 8, 136, 14, 2, 64, 1, 0, 96, 0, 0, 94, + 3, 2, 3, 0, 6, 108, 0, 15, 104, 8, 7, 12, 114, 0, 254, 1, 178, 74, 165, 72, 52, 89, + 207, 36, 174, 158, 90, 29, 170, 210, 239, 251, 176, 4, 8, 136, 0, 47, 248, 194, 136, 0, + 69, 255, 1, 22, 2, 171, 112, 150, 128, 196, 25, 7, 108, 1, 7, 155, 56, 73, 212, 136, 0, + 11, 47, 80, 206, 136, 0, 69, 254, 1, 107, 215, 2, 229, 17, 21, 194, 39, 28, 213, 144, + 236, 110, 145, 245, 168, 136, 0, 8, 80, 5, 119, 158, 221, 91, 93, 1, 0, 64, 80, 5, 0, + 152, 1, 0, 146, 1, 6, 80, 5, 16, 106, 170, 1, 1, 22, 0, 0, 70, 35, 13, 65, 35, 1, 240, + 28, 1, 80, 2, 7, 232, 4, 127, 21, 243, 152, 93, 1, 0, 18, 40, 22, 4, 19, 249, 82, 0, + 15, 232, 4, 15, 23, 159, 136, 25, 15, 232, 4, 8, 33, 88, 232, 232, 4, 0, 204, 73, 11, + 137, 25, 3, 156, 4, 4, 232, 4, 107, 110, 70, 118, 75, 117, 120, 21, 0, 88, 104, 84, 68, + 78, 99, 27, 22, 88, 104, 120, 82, 104, 111, 18, 23, 99, 110, 66, 114, 99, 117, 69, 55, + 0, 0, 10, 5, 103, 71, 70, 74, 82, 65, 74, 17, 0, 103, 105, 83, 111, 69, 68, 82, 17, 0, + 88, 74, 100, 83, 117, 106, 61, 22, 96, 102, 80, 89, 74, 87, 122, 162, 0, 3, 0, 4, 8, + 32, 5, 59, 190, 31, 154, 32, 5, 0, 122, 28, 4, 32, 5, 3, 209, 0, 11, 32, 5, 8, 32, 22, + 32, 147, 43, 64, 0, 8, 240, 18, 2, 66, 13, 0, 152, 1, 8, 40, 0, 44, 235, 93, 40, 0, 2, + 186, 27, 4, 24, 16, 33, 192, 15, 15, 0, 13, 24, 16, 31, 176, 24, 16, 0, 0, 192, 4, 33, + 198, 3, 47, 0, 48, 0, 16, 185, 88, 0, 8, 160, 5, 16, 14, 24, 0, 1, 198, 0, 68, 0, 8, 0, + 188, 72, 19, 2, 134, 28, 7, 42, 5, 1, 128, 4, 2, 192, 4, 13, 136, 28, 0, 76, 4, 240, 1, + 105, 150, 63, 86, 53, 77, 161, 27, 239, 86, 227, 182, 112, 9, 63, 210, 47, 0, 3, 64, 1, + 0, 192, 4, 4, 128, 0, 59, 42, 70, 155, 192, 4, 2, 128, 0, 32, 125, 33, 84, 4, 28, 45, + 118, 0, 5, 192, 4, 249, 0, 137, 253, 222, 11, 80, 170, 106, 215, 105, 161, 202, 88, + 235, 37, 175, 192, 4, 0, 224, 0, 4, 32, 5, 59, 108, 105, 157, 128, 6, 6, 96, 0, 8, 224, + 0, 13, 106, 0, 7, 160, 5, 15, 108, 0, 2, 240, 1, 111, 153, 142, 36, 235, 179, 134, 158, + 174, 211, 201, 43, 220, 41, 23, 234, 86, 0, 7, 224, 0, 4, 128, 0, 32, 225, 120, 128, 0, + 8, 160, 5, 2, 128, 0, 32, 51, 36, 224, 0, 28, 48, 118, 0, 5, 224, 0, 255, 1, 133, 255, + 60, 94, 200, 40, 18, 137, 10, 139, 54, 169, 226, 68, 104, 53, 160, 5, 5, 32, 9, 131, + 96, 0, 8, 160, 5, 6, 96, 0, 0, 14, 4, 2, 3, 0, 6, 108, 0, 15, 160, 5, 7, 12, 114, 0, + 254, 1, 20, 239, 51, 195, 161, 65, 40, 180, 51, 37, 184, 202, 190, 76, 183, 206, 144, + 4, 8, 160, 5, 47, 113, 214, 136, 0, 69, 255, 1, 182, 8, 240, 96, 24, 93, 170, 112, 67, + 171, 54, 115, 215, 233, 120, 20, 136, 0, 11, 47, 177, 225, 136, 0, 69, 255, 1, 88, 221, + 47, 81, 251, 193, 42, 182, 189, 8, 128, 199, 178, 226, 188, 140, 136, 0, 11, 47, 221, + 236, 136, 0, 69, 255, 1, 18, 59, 38, 249, 170, 102, 14, 69, 202, 7, 203, 117, 45, 152, + 24, 147, 136, 0, 11, 47, 99, 246, 136, 0, 70, 255, 0, 105, 46, 111, 111, 5, 201, 1, + 179, 245, 173, 31, 227, 34, 160, 139, 136, 0, 11, 47, 154, 255, 136, 0, 69, 254, 1, + 185, 111, 162, 88, 230, 145, 168, 231, 255, 197, 46, 196, 199, 23, 22, 175, 136, 0, 8, + 56, 7, 59, 228, 151, 168, 56, 7, 0, 48, 3, 0, 42, 3, 15, 56, 7, 6, 12, 41, 36, 5, 56, + 7, 8, 216, 49, 74, 183, 141, 193, 93, 232, 31, 17, 17, 136, 3, 6, 80, 13, 9, 136, 9, 7, + 74, 13, 12, 231, 12, 1, 234, 3, 5, 236, 12, 0, 8, 6, 8, 232, 31, 74, 2, 233, 195, 93, + 232, 31, 16, 64, 74, 5, 82, 8, 224, 230, 0, 250, 242, 24, 0, 200, 13, 8, 108, 0, 15, + 28, 27, 2, 13, 72, 10, 32, 11, 243, 88, 0, 8, 168, 4, 2, 192, 0, 0, 94, 0, 15, 232, 31, + 37, 8, 168, 20, 74, 16, 149, 197, 93, 0, 28, 6, 96, 0, 0, 126, 1, 0, 248, 21, 2, 186, + 0, 15, 248, 21, 33, 15, 228, 0, 2, 10, 248, 21, 15, 0, 28, 12, 4, 176, 5, 32, 15, 163, + 168, 0, 8, 16, 7, 6, 168, 0, 15, 102, 1, 9, 15, 0, 28, 45, 4, 128, 0, 63, 234, 151, + 198, 136, 1, 2, 32, 53, 102, 196, 5, 2, 26, 23, 7, 134, 7, 5, 48, 6, 15, 144, 15, 2, 4, + 144, 6, 7, 136, 1, 32, 178, 177, 96, 0, 14, 136, 1, 0, 96, 0, 4, 136, 1, 2, 102, 0, 15, + 136, 1, 33, 15, 134, 0, 2, 10, 136, 1, 15, 128, 23, 20, 47, 145, 189, 168, 0, 108, 15, + 128, 23, 20, 47, 156, 197, 168, 0, 108, 15, 128, 23, 20, 47, 209, 204, 168, 0, 108, 15, + 128, 23, 20, 47, 227, 211, 168, 0, 108, 15, 128, 23, 8, 8, 64, 19, 74, 183, 98, 201, + 93, 64, 19, 2, 40, 4, 6, 240, 5, 15, 64, 19, 47, 8, 96, 6, 74, 141, 59, 14, 95, 96, 6, + 27, 18, 112, 0, 8, 244, 5, 8, 170, 19, 15, 96, 6, 27, 74, 100, 249, 15, 95, 96, 6, 33, + 177, 144, 72, 38, 20, 176, 10, 12, 2, 166, 5, 6, 132, 4, 15, 124, 5, 2, 13, 96, 6, 74, + 103, 14, 16, 95, 96, 6, 2, 192, 0, 0, 94, 0, 15, 96, 6, 49, 74, 8, 131, 17, 95, 96, 6, + 6, 96, 0, 4, 216, 4, 2, 186, 0, 15, 216, 4, 33, 15, 228, 0, 2, 10, 216, 4, 15, 96, 6, + 20, 32, 235, 151, 168, 0, 8, 96, 6, 6, 168, 0, 15, 102, 1, 9, 15, 96, 6, 53, 63, 78, + 90, 19, 136, 1, 2, 47, 213, 214, 96, 6, 51, 32, 51, 110, 96, 0, 8, 96, 6, 2, 224, 0, 0, + 96, 0, 4, 136, 1, 15, 96, 6, 113, 47, 100, 121, 168, 0, 108, 15, 96, 6, 4, 4, 208, 15, + 16, 16, 173, 2, 48, 0, 0, 0, 40, 10, 0, 65, 1, 20, 46, 233, 7, 16, 16, 43, 23, 32, 0, + 3, 20, 0, 0, 3, 0, 0, 104, 3, 83, 176, 173, 1, 0, 61, 18, 0, 211, 96, 87, 213, 179, 0, + 0, 29, 0, 60, 244, 0, 0, 2, 16, 106, 2, 96, 75, 130, 1, 0, 50, 56, 52, 46, 48, 46, 75, + 88, 0, 56, 0, 23, 208, 56, 0, 32, 145, 121, 56, 0, 49, 14, 0, 134, 56, 0, 34, 0, 1, 66, + 4, 2, 64, 8, 38, 17, 174, 96, 0, 64, 52, 200, 28, 182, 230, 60, 32, 64, 246, 96, 0, 0, + 40, 79, 70, 2, 0, 80, 144, 32, 0, 144, 213, 206, 44, 182, 0, 0, 6, 0, 82, 162, 50, 3, + 160, 0, 38, 32, 148, 32, 0, 64, 4, 15, 96, 187, 64, 0, 32, 107, 93, 154, 23, 0, 32, 0, + 85, 4, 2, 192, 107, 7, 32, 0, 211, 7, 213, 124, 187, 0, 0, 59, 0, 70, 164, 5, 0, 11, + 32, 106, 16, 29, 49, 0, 1, 182, 0, 0, 81, 0, 0, 9, 1, 7, 152, 66, 0, 41, 11, 18, 46, + 218, 110, 98, 97, 99, 116, 105, 118, 101, 40, 0, 1, 224, 0, 22, 182, 120, 0, 176, 129, + 143, 244, 187, 0, 0, 19, 0, 180, 60, 1, 24, 1, 1, 144, 170, 97, 5, 0, 84, 68, 84, 70, + 47, 0, 1, 232, 0, 23, 80, 48, 0, 32, 156, 168, 48, 0, 65, 49, 0, 204, 57, 48, 0, 18, 4, + 48, 0, 17, 2, 169, 18, 68, 0, 0, 224, 63, 10, 0, 0, 18, 68, 1, 65, 0, 39, 0, 0, 78, 0, + 0, 216, 0, 70, 2, 2, 64, 170, 128, 0, 161, 84, 245, 246, 187, 0, 0, 18, 0, 250, 219, + 56, 1, 51, 1, 0, 8, 65, 67, 3, 60, 0, 1, 128, 0, 22, 169, 48, 0, 160, 63, 182, 247, + 187, 0, 0, 113, 0, 50, 217, 40, 1, 2, 176, 0, 241, 23, 99, 0, 60, 84, 77, 84, 105, 109, + 101, 90, 111, 110, 101, 77, 97, 110, 97, 103, 101, 114, 58, 32, 48, 120, 55, 102, 97, + 56, 48, 56, 54, 48, 53, 51, 52, 48, 32, 123, 237, 207, 2, 4, 0, 34, 76, 111, 124, 100, + 97, 32, 48, 32, 45, 45, 44, 25, 0, 212, 77, 111, 98, 105, 108, 101, 76, 111, 99, 107, + 100, 111, 119, 25, 0, 178, 125, 32, 61, 32, 40, 110, 117, 108, 108, 41, 62, 142, 0, 2, + 192, 0, 23, 32, 192, 0, 32, 170, 188, 144, 0, 64, 19, 0, 119, 217, 192, 0, 2, 144, 0, + 98, 5, 0, 105, 110, 105, 116, 50, 0, 1, 192, 0, 22, 183, 192, 0, 64, 203, 144, 12, 188, + 112, 1, 33, 215, 65, 64, 1, 3, 48, 0, 6, 34, 1, 1, 48, 0, 22, 162, 48, 0, 32, 252, 159, + 48, 0, 32, 58, 0, 38, 1, 228, 2, 0, 0, 5, 0, 8, 11, 187, 131, 51, 83, 61, 9, 64, 232, + 104, 96, 240, 127, 0, 8, 154, 153, 1, 0, 37, 169, 63, 20, 0, 23, 255, 10, 0, 5, 136, 0, + 38, 48, 180, 88, 0, 32, 110, 164, 88, 0, 65, 28, 0, 201, 20, 128, 41, 20, 2, 48, 0, 0, + 212, 6, 0, 48, 0, 4, 3, 0, 12, 136, 2, 79, 199, 28, 13, 188, 136, 2, 1, 19, 255, 1, 0, + 2, 208, 53, 15, 136, 2, 19, 83, 240, 174, 1, 0, 85, 160, 3, 64, 149, 93, 66, 188, 18, + 67, 33, 5, 255, 216, 1, 22, 2, 72, 2, 0, 34, 1, 3, 120, 1, 22, 176, 48, 0, 64, 31, 204, + 255, 192, 171, 0, 33, 158, 0, 192, 0, 1, 48, 3, 68, 48, 105, 93, 4, 80, 0, 211, 245, + 244, 134, 194, 0, 0, 140, 0, 40, 69, 42, 4, 13, 82, 227, 34, 68, 0, 158, 0, 49, 34, 4, + 68, 228, 62, 240, 14, 88, 0, 20, 0, 45, 91, 78, 87, 67, 111, 110, 99, 114, 101, 116, + 101, 95, 110, 119, 95, 114, 101, 115, 111, 108, 118, 101, 114, 32, 195, 1, 240, 9, 87, + 105, 116, 104, 69, 110, 100, 112, 111, 105, 110, 116, 58, 112, 97, 114, 97, 109, 101, + 116, 101, 114, 115, 58, 150, 67, 248, 15, 58, 108, 111, 103, 95, 115, 116, 114, 58, 93, + 0, 72, 111, 115, 116, 110, 97, 109, 101, 35, 53, 49, 51, 100, 52, 57, 101, 53, 58, 48, + 141, 67, 5, 255, 62, 0, 83, 1, 0, 168, 0, 83, 80, 107, 93, 4, 86, 168, 0, 176, 158, + 203, 136, 194, 0, 0, 64, 0, 56, 223, 14, 168, 0, 1, 152, 4, 19, 44, 168, 0, 7, 143, 0, + 82, 95, 115, 101, 116, 95, 113, 177, 240, 5, 95, 104, 97, 110, 100, 108, 101, 114, 95, + 98, 108, 111, 99, 107, 95, 105, 110, 118, 111, 107, 72, 158, 2, 240, 63, 4, 0, 1, 223, + 84, 247, 167, 194, 0, 0, 155, 0, 115, 213, 3, 4, 15, 112, 68, 6, 0, 6, 1, 17, 60, 12, + 1, 63, 80, 0, 31, 112, 68, 6, 255, 1, 245, 174, 137, 66, 122, 148, 70, 161, 173, 248, + 207, 46, 79, 95, 7, 99, 240, 0, 21, 37, 117, 110, 92, 68, 128, 32, 40, 78, 111, 32, + 110, 101, 116, 95, 102, 101, 32, 114, 111, 117, 116, 101, 192, 177, 100, 3, 2, 240, + 171, 1, 0, 16, 1, 145, 168, 113, 17, 232, 0, 0, 46, 0, 87, 246, 1, 64, 0, 128, 205, + 238, 88, 3, 181, 0, 3, 0, 8, 110, 26, 115, 136, 204, 37, 15, 248, 2, 0, 170, 2, 32, + 138, 110, 46, 0, 0, 74, 0, 102, 4, 0, 3, 2, 176, 172, 72, 0, 32, 152, 141, 26, 0, 21, + 16, 72, 0, 32, 253, 242, 88, 2, 0, 72, 2, 70, 3, 2, 64, 166, 8, 3, 117, 147, 81, 19, + 232, 0, 0, 31, 40, 0, 32, 12, 198, 40, 0, 2, 200, 3, 36, 9, 0, 41, 4, 2, 56, 0, 38, + 240, 165, 56, 0, 64, 97, 16, 20, 232, 8, 3, 4, 168, 0, 32, 186, 198, 168, 0, 32, 34, 3, + 174, 2, 247, 14, 12, 0, 66, 4, 12, 0, 9, 0, 2, 8, 49, 16, 47, 72, 45, 34, 15, 64, 117, + 110, 97, 118, 97, 105, 108, 97, 98, 108, 101, 84, 0, 4, 184, 0, 8, 224, 4, 117, 200, + 19, 21, 232, 0, 0, 121, 144, 0, 38, 60, 222, 144, 0, 15, 232, 4, 91, 55, 3, 2, 128, + 232, 4, 32, 10, 31, 152, 0, 6, 40, 1, 33, 129, 222, 240, 0, 15, 40, 1, 3, 22, 171, 136, + 1, 64, 238, 83, 158, 242, 208, 1, 17, 164, 179, 29, 8, 208, 1, 121, 40, 46, 166, 29, + 39, 72, 16, 208, 1, 32, 19, 81, 46, 0, 4, 24, 1, 23, 16, 168, 1, 64, 5, 22, 159, 242, + 168, 1, 4, 72, 0, 38, 141, 196, 24, 1, 15, 168, 1, 9, 32, 84, 30, 56, 0, 21, 57, 56, 0, + 33, 59, 197, 184, 0, 1, 168, 1, 81, 10, 0, 66, 4, 10, 168, 1, 143, 84, 99, 220, 233, + 219, 71, 16, 64, 166, 1, 5, 2, 0, 2, 8, 168, 1, 32, 42, 96, 88, 0, 21, 121, 88, 0, 38, + 167, 220, 144, 0, 15, 168, 1, 93, 23, 96, 168, 1, 32, 64, 99, 152, 0, 21, 31, 152, 0, + 33, 236, 220, 240, 0, 15, 168, 1, 2, 8, 208, 0, 32, 144, 127, 56, 0, 6, 208, 0, 47, + 168, 210, 208, 0, 49, 31, 49, 96, 7, 32, 55, 3, 2, 96, 152, 0, 32, 170, 129, 152, 0, 6, + 208, 0, 47, 237, 210, 208, 0, 7, 8, 72, 4, 49, 120, 27, 187, 120, 2, 19, 175, 248, 1, + 6, 72, 4, 106, 7, 67, 247, 142, 21, 74, 120, 2, 32, 216, 24, 46, 0, 15, 120, 2, 1, 32, + 86, 245, 26, 0, 21, 31, 72, 0, 15, 120, 2, 21, 32, 193, 253, 56, 0, 21, 57, 56, 0, 15, + 120, 2, 3, 111, 234, 126, 235, 22, 195, 73, 120, 2, 25, 49, 54, 62, 188, 168, 1, 4, + 144, 0, 15, 120, 2, 51, 15, 168, 1, 36, 7, 120, 2, 32, 105, 65, 152, 0, 6, 40, 1, 15, + 120, 2, 7, 2, 168, 7, 4, 240, 5, 95, 234, 15, 126, 92, 1, 168, 7, 0, 0, 6, 10, 15, 168, + 7, 113, 4, 80, 7, 32, 182, 242, 168, 0, 14, 168, 7, 0, 168, 0, 15, 168, 7, 27, 70, 2, + 2, 32, 178, 32, 5, 64, 104, 49, 192, 93, 64, 77, 32, 179, 9, 16, 10, 50, 0, 14, 0, 80, + 6, 244, 8, 4, 133, 126, 170, 131, 0, 4, 10, 43, 135, 218, 0, 4, 166, 19, 142, 229, 0, + 4, 227, 24, 36, 242, 12, 0, 68, 207, 28, 37, 242, 36, 0, 68, 250, 255, 40, 222, 54, 0, + 0, 194, 2, 10, 12, 0, 16, 16, 18, 0, 1, 216, 2, 55, 2, 2, 144, 120, 0, 32, 211, 117, + 120, 0, 64, 114, 0, 233, 10, 120, 0, 49, 34, 12, 2, 54, 0, 3, 6, 0, 80, 8, 186, 220, + 191, 93, 80, 12, 96, 2, 8, 38, 149, 227, 97, 67, 0, 80, 2, 8, 207, 110, 14, 9, 0, 246, + 6, 0, 2, 8, 192, 240, 99, 47, 136, 6, 141, 63, 2, 8, 196, 29, 81, 156, 1, 0, 48, 63, + 206, 89, 80, 14, 0, 2, 4, 123, 48, 0, 2, 74, 0, 1, 112, 9, 144, 49, 55, 46, 50, 53, 51, + 46, 50, 48, 7, 0, 0, 23, 0, 3, 144, 0, 8, 8, 1, 79, 176, 168, 12, 95, 8, 1, 7, 68, 172, + 57, 84, 222, 252, 0, 68, 115, 128, 237, 246, 12, 0, 68, 97, 225, 239, 246, 8, 1, 74, 0, + 173, 188, 227, 252, 0, 1, 106, 0, 3, 18, 0, 17, 84, 7, 0, 2, 120, 0, 8, 8, 1, 32, 56, + 190, 120, 0, 8, 8, 1, 0, 178, 0, 4, 8, 1, 32, 132, 96, 30, 0, 0, 204, 12, 6, 8, 1, 36, + 228, 183, 8, 1, 255, 2, 10, 184, 254, 149, 73, 152, 149, 63, 2, 8, 107, 202, 176, 178, + 255, 255, 84, 8, 1, 19, 47, 49, 52, 8, 1, 8, 79, 38, 21, 62, 96, 8, 1, 7, 68, 184, 69, + 231, 227, 252, 0, 68, 196, 86, 18, 252, 12, 0, 68, 58, 192, 19, 252, 8, 1, 79, 203, 7, + 221, 232, 8, 1, 7, 17, 28, 188, 0, 14, 8, 1, 32, 1, 32, 120, 0, 8, 8, 1, 0, 218, 2, 4, + 8, 1, 65, 56, 224, 61, 96, 24, 1, 7, 16, 2, 34, 90, 6, 91, 31, 240, 119, 2, 8, 158, 53, + 241, 110, 98, 209, 147, 63, 2, 8, 143, 184, 235, 152, 255, 255, 59, 63, 2, 4, 1, 0, 0, + 0, 34, 4, 0, 0, 14, 0, 2, 4, 123, 0, 0, 0, 2, 4, 0, 0, 0, 0, 2, 4, 1, 0, 0, 0, 49, 55, + 46, 50, 53, 51, 46, 49, 52, 46, 50, 53, 49, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 2, 240, 171, + 1, 0, 85, 3, 0, 0, 0, 0, 0, 0, 210, 19, 63, 96, 1, 0, 38, 0, 205, 238, 0, 0, 2, 0, 0, + 3, 0, 8, 48, 226, 84, 206, 139, 163, 23, 64, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 109, + 16, 63, 96, 1, 0, 0, 0, 0, 0, 98, 118, 52, 36, + ]; + let (_, chunkset) = ChunksetChunk::parse_chunkset(&test_data).unwrap(); + assert_eq!(chunkset.chunk_tag, 0x600d); + assert_eq!(chunkset.chunk_sub_tag, 17); + assert_eq!(chunkset.chunk_data_size, 20758); + assert_eq!(chunkset.signature, 825521762); // "bv41" + assert_eq!(chunkset.uncompress_size, 62592); + assert_eq!(chunkset.block_size, 20742); + assert_eq!(chunkset.decompressed_data.len(), 62592); + assert_eq!(chunkset.footer, 607417954); // "bv4$" + } + + #[test] + fn test_parse_chunkset_data() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Chunkset Tests/big_sur_chunkset.raw"); + + let buffer = fs::read(test_path).unwrap(); + let mut unified_log = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + let (_, _) = ChunksetChunk::parse_chunkset_data(&buffer, &mut unified_log).unwrap(); + assert_eq!(unified_log.catalog.chunk_tag, 0); + assert_eq!(unified_log.firehose.len(), 26); + assert_eq!(unified_log.statedump.len(), 0); + assert_eq!(unified_log.simpledump.len(), 0); + assert_eq!(unified_log.oversize.len(), 0); + + assert_eq!( + unified_log.firehose[0].public_data[0].message.item_info[0].message_strings, + "796.100" + ); + assert_eq!(unified_log.firehose[0].base_continous_time, 0); + assert_eq!(unified_log.firehose[0].first_number_proc_id, 105); + assert_eq!(unified_log.firehose[0].second_number_proc_id, 236); + assert_eq!(unified_log.firehose[0].public_data_size, 3936); + assert_eq!(unified_log.firehose[0].private_data_virtual_offset, 4096); + } + + #[test] + fn test_parse_firehose_chunkset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Chunkset Tests/big_sur_firehose_chunkset.raw"); + + let buffer = fs::read(test_path).unwrap(); + let mut unified_log = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + let firehose_chunk: u32 = 0x6001; + ChunksetChunk::get_chunkset_data(&buffer, firehose_chunk, &mut unified_log); + assert_eq!(unified_log.firehose.len(), 1); + assert_eq!( + unified_log.firehose[0].public_data[0].message.item_info[0].message_strings, + "796.100" + ); + assert_eq!(unified_log.firehose[0].base_continous_time, 0); + assert_eq!(unified_log.firehose[0].first_number_proc_id, 105); + assert_eq!(unified_log.firehose[0].second_number_proc_id, 236); + assert_eq!(unified_log.firehose[0].public_data_size, 3936); + assert_eq!(unified_log.firehose[0].private_data_virtual_offset, 4096); + } + + #[test] + fn test_parse_oversize_chunkset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Chunkset Tests/big_sur_oversize_chunkset.raw"); + let buffer = fs::read(test_path).unwrap(); + + let mut unified_log = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + let oversize_chunk: u32 = 0x6002; + ChunksetChunk::get_chunkset_data(&buffer, oversize_chunk, &mut unified_log); + assert_eq!(unified_log.oversize.len(), 1); + assert_eq!( + unified_log.oversize[0].message_items.item_info[0].message_strings, + "system kext collection" + ); + assert_eq!( + unified_log.oversize[0].message_items.item_info[0].item_type, + 34 + ); + assert_eq!(unified_log.oversize[0].first_proc_id, 96); + assert_eq!(unified_log.oversize[0].second_proc_id, 245); + assert_eq!(unified_log.oversize[0].continuous_time, 5609252490); + assert_eq!(unified_log.oversize[0].public_data_size, 1092); + assert_eq!(unified_log.oversize[0].private_data_size, 0); + } + + #[test] + fn test_parse_statedump_chunkset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Chunkset Tests/big_sur_statedump_chunkset.raw"); + let buffer = fs::read(test_path).unwrap(); + + let mut unified_log = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + let statedump_chunk = 0x6003; + ChunksetChunk::get_chunkset_data(&buffer, statedump_chunk, &mut unified_log); + assert_eq!(unified_log.statedump.len(), 1); + println!("{:?}", unified_log.statedump); + assert_eq!( + unified_log.statedump[0].unknown_name, + "CLDaemonStatusStateTracker" + ); + assert_eq!( + unified_log.statedump[0].statedump_data, + [ + 0, 0, 0, 0, 0, 0, 240, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ); + assert_eq!( + unified_log.statedump[0].unknown_object_type_string_2, + "_CLDaemonStatusStateTrackerState" + ); + assert_eq!( + unified_log.statedump[0].unknown_object_type_string_1, + "location" + ); + assert_eq!(unified_log.statedump[0].continuous_time, 3906319117); + assert_eq!(unified_log.statedump[0].first_proc_id, 113); + assert_eq!(unified_log.statedump[0].second_proc_id, 464); + assert_eq!(unified_log.statedump[0].activity_id, 9223372036854776950); + assert_eq!( + unified_log.statedump[0].uuid, + "5CD8DDEE04383A38887710227C5A0A56" + ); + assert_eq!(unified_log.statedump[0].chunk_data_size, 288); + } + + #[test] + fn test_parse_simpledump_chunkset() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Chunkset Tests/monterey_chunkset_simpledump.raw"); + + let buffer = fs::read(test_path).unwrap(); + + let mut unified_log = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + let simpledump_chunk = 0x6004; + ChunksetChunk::get_chunkset_data(&buffer, simpledump_chunk, &mut unified_log); + assert_eq!(unified_log.simpledump.len(), 1); + println!("{:?}", unified_log.simpledump); + assert_eq!( + unified_log.simpledump[0].message_string, + "service exited: dirty = 0, supported pressured-exit = 1" + ); + assert_eq!(unified_log.simpledump[0].first_proc_id, 1); + assert_eq!(unified_log.simpledump[0].second_proc_id, 1); + assert_eq!(unified_log.simpledump[0].continous_time, 4970481235501); + assert_eq!(unified_log.simpledump[0].thread_id, 59907); + assert_eq!(unified_log.simpledump[0].unknown_size_message_string, 56); + assert_eq!(unified_log.simpledump[0].unknown_size_subsystem_string, 79); + assert_eq!(unified_log.simpledump[0].unknown_offset, 95862); + assert_eq!( + unified_log.simpledump[0].subsystem, + "user/501/com.apple.mdworker.shared.0B000000-0000-0000-0000-000000000000 [4229]" + ); + assert_eq!(unified_log.simpledump[0].first_proc_id, 1); + } +} diff --git a/src/dsc.rs b/src/dsc.rs new file mode 100755 index 0000000..10a06ab --- /dev/null +++ b/src/dsc.rs @@ -0,0 +1,325 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use crate::util::extract_string; + +use log::error; +use nom::bytes::complete::take; +use nom::number::complete::{be_u128, le_u16, le_u32, le_u64}; +use nom::Needed; +use std::mem::size_of; + +#[derive(Debug)] +pub struct SharedCacheStrings { + pub signature: u32, + pub major_version: u16, // Version 1 up to Big Sur. Monterey has Version 2! + pub minor_version: u16, + pub number_ranges: u32, + pub number_uuids: u32, + pub ranges: Vec, + pub uuids: Vec, + pub dsc_uuid: String, +} + +#[derive(Debug)] +pub struct RangeDescriptor { + pub range_offset: u64, // In Major version 2 this is 8 bytes, in version 1 its 4 bytes + pub data_offset: u32, + pub range_size: u32, + pub unknown_uuid_index: u64, // Unknown value, added in Major version: 2. Appears to be UUID index. In version 1 the index is 4 bytes and is at the start of the range descriptor + pub strings: Vec, +} + +#[derive(Debug)] +pub struct UUIDDescriptor { + pub text_offset: u64, // Size appears to be 8 bytes in Major version: 2. 4 bytes in Major Version 1 + pub text_size: u32, + pub uuid: String, + pub path_offset: u32, + pub path_string: String, // Not part of format +} + +impl SharedCacheStrings { + /// Parse shared strings data (the file(s) in /private/var/db/uuidtext/dsc) + pub fn parse_dsc(data: &[u8]) -> nom::IResult<&[u8], SharedCacheStrings> { + let (input, sig) = take(size_of::())(data)?; + let (_, dsc_sig) = le_u32(sig)?; + + let expected_dsc_signature = 0x64736368; + if expected_dsc_signature != dsc_sig { + error!( + "[macos-unifiedlogs] Incorrect DSC file signature. Expected {}. Got: {}", + expected_dsc_signature, dsc_sig + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + + let (input, major) = take(size_of::())(input)?; + let (input, minor) = take(size_of::())(input)?; + let (input, number_ranges) = take(size_of::())(input)?; + let (mut input, number_uuids) = take(size_of::())(input)?; + + let (_, dsc_major) = le_u16(major)?; + let (_, dsc_minor) = le_u16(minor)?; + let (_, dsc_number_ranges) = le_u32(number_ranges)?; + let (_, dsc_number_uuids) = le_u32(number_uuids)?; + + let mut shared_cache_strings = SharedCacheStrings { + signature: dsc_sig, + major_version: dsc_major, + minor_version: dsc_minor, + number_ranges: dsc_number_ranges, + number_uuids: dsc_number_uuids, + ranges: Vec::new(), + uuids: Vec::new(), + dsc_uuid: String::new(), + }; + + let mut range_count = 0; + while range_count < shared_cache_strings.number_ranges { + let (range_input, range_data) = SharedCacheStrings::get_ranges(input, &dsc_major)?; + input = range_input; + shared_cache_strings.ranges.push(range_data); + range_count += 1; + } + + let mut uuid_count = 0; + while uuid_count < shared_cache_strings.number_uuids { + let (uuid_input, uuid_data) = SharedCacheStrings::get_uuids(input, &dsc_major)?; + input = uuid_input; + shared_cache_strings.uuids.push(uuid_data); + uuid_count += 1; + } + + for uuids in &mut shared_cache_strings.uuids { + let (_, path_string) = SharedCacheStrings::get_paths(data, uuids.path_offset)?; + uuids.path_string = path_string; + } + + for range in &mut shared_cache_strings.ranges { + let (_, strings) = + SharedCacheStrings::get_strings(data, range.data_offset, range.range_size)?; + range.strings = strings; + } + + Ok((input, shared_cache_strings)) + } + + // Get range data, used by log entries to determine where the base string entry is located. + fn get_ranges<'a>(data: &'a [u8], version: &u16) -> nom::IResult<&'a [u8], RangeDescriptor> { + let version_number: u16 = 2; + let mut input = data; + let mut range_data = RangeDescriptor { + range_offset: 0, + data_offset: 0, + range_size: 0, + unknown_uuid_index: 0, + strings: Vec::new(), + }; + + // Version 2 (Monterey and higher) changed the Range format a bit + // range offset is now 8 bytes (vs 4 bytes) and starts at beginning + // The uuid index was moved to end + range_data.range_offset = if version == &version_number { + let (data_input, value_range_offset) = take(size_of::())(input)?; + input = data_input; + let (_, dsc_range_offset) = le_u64(value_range_offset)?; + dsc_range_offset + } else { + // Get data based on version 1 + let (data_input, uuid_descriptor_index) = take(size_of::())(input)?; + let (_, dsc_uuid_descriptor_index) = le_u32(uuid_descriptor_index)?; + range_data.unknown_uuid_index = u64::from(dsc_uuid_descriptor_index); + + let (data_input, value_range_offset) = take(size_of::())(data_input)?; + input = data_input; + let (_, dsc_range_offset) = le_u32(value_range_offset)?; + u64::from(dsc_range_offset) + }; + + let (input, data_offset) = take(size_of::())(input)?; + let (mut input, range_size) = take(size_of::())(input)?; + + let (_, dsc_data_offset) = le_u32(data_offset)?; + let (_, dsc_range_size) = le_u32(range_size)?; + + range_data.data_offset = dsc_data_offset; + range_data.range_size = dsc_range_size; + + // UUID index is now located at the end of the format (instead of beginning) + if version == &version_number { + let (version_two_input, unknown) = take(size_of::())(input)?; + let (_, dsc_unknown) = le_u64(unknown)?; + range_data.unknown_uuid_index = dsc_unknown; + input = version_two_input; + } + Ok((input, range_data)) + } + + // Get UUID entries related to ranges + fn get_uuids<'a>(data: &'a [u8], version: &u16) -> nom::IResult<&'a [u8], UUIDDescriptor> { + let mut uuid_data = UUIDDescriptor { + text_offset: 0, + text_size: 0, + uuid: String::new(), + path_offset: 0, + path_string: String::new(), + }; + + let version_number: u16 = 2; + let mut input = data; + if version == &version_number { + let (version_two_input, text_offset) = take(size_of::())(input)?; + let (_, dsc_text_offset) = le_u64(text_offset)?; + uuid_data.text_offset = dsc_text_offset; + input = version_two_input; + } else { + let (version_one_input, text_offset) = take(size_of::())(input)?; + let (_, dsc_text_offset) = le_u32(text_offset)?; + uuid_data.text_offset = u64::from(dsc_text_offset); + input = version_one_input; + } + + let (input, text_size) = take(size_of::())(input)?; + let (input, uuid) = take(size_of::())(input)?; + let (input, path_offset) = take(size_of::())(input)?; + + let (_, dsc_text_size) = le_u32(text_size)?; + let (_, dsc_uuid) = be_u128(uuid)?; + let (_, dsc_path_offset) = le_u32(path_offset)?; + + uuid_data.text_size = dsc_text_size; + uuid_data.uuid = format!("{:X}", dsc_uuid); + uuid_data.path_offset = dsc_path_offset; + + Ok((input, uuid_data)) + } + + fn get_paths(data: &[u8], path_offset: u32) -> nom::IResult<&[u8], String> { + let (nom_path_offset, _) = take(path_offset)(data)?; + let (_, path) = extract_string(nom_path_offset)?; + Ok((nom_path_offset, path)) + } + + // After parsing the ranges and UUIDs remaining data are the base log entry strings + fn get_strings( + data: &[u8], + string_offset: u32, + string_range: u32, + ) -> nom::IResult<&[u8], Vec> { + let (nom_string_offset, _) = take(string_offset)(data)?; + let (_, strings) = take(string_range)(nom_string_offset)?; + Ok((&[], strings.to_vec())) + } +} + +#[cfg(test)] +mod tests { + use crate::dsc::SharedCacheStrings; + use std::fs; + use std::path::PathBuf; + + #[test] + fn test_parse_dsc_version_one() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path + .push("tests/test_data/DSC Tests/big_sur_version_1_522F6217CB113F8FB845C2A1B784C7C2"); + + let buffer = fs::read(test_path).unwrap(); + + let (_, results) = SharedCacheStrings::parse_dsc(&buffer).unwrap(); + assert_eq!(results.uuids.len(), 532); + assert_eq!(results.uuids[0].uuid, "4DF6D8F5D9C23A968DE45E99D6B73DC8"); + assert_eq!(results.uuids[0].path_offset, 19919502); + assert_eq!(results.uuids[0].text_size, 8192); + assert_eq!(results.uuids[0].text_offset, 73728); + assert_eq!( + results.uuids[0].path_string, + "/usr/lib/system/libsystem_blocks.dylib" + ); + + assert_eq!(results.ranges.len(), 788); + assert_eq!(results.ranges[0].strings, [0]); + assert_eq!(results.ranges[0].unknown_uuid_index, 0); + assert_eq!(results.ranges[0].range_offset, 80296); + assert_eq!(results.ranges[0].range_size, 1); + + assert_eq!(results.signature, 1685283688); // hcsd + assert_eq!(results.major_version, 1); + assert_eq!(results.minor_version, 0); + assert_eq!(results.dsc_uuid, ""); + assert_eq!(results.number_ranges, 788); + assert_eq!(results.number_uuids, 532); + } + + #[test] + fn test_parse_dsc_version_two() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path + .push("tests/test_data/DSC Tests/monterey_version_2_3D05845F3F65358F9EBF2236E772AC01"); + + let buffer = fs::read(test_path).unwrap(); + + let (_, results) = SharedCacheStrings::parse_dsc(&buffer).unwrap(); + assert_eq!(results.uuids.len(), 2250); + assert_eq!(results.uuids[0].uuid, "326DD91B4EF83D80B90BF50EB7D7FDB8"); + assert_eq!(results.uuids[0].path_offset, 98376932); + assert_eq!(results.uuids[0].text_size, 8192); + assert_eq!(results.uuids[0].text_offset, 327680); + assert_eq!( + results.uuids[0].path_string, + "/usr/lib/system/libsystem_blocks.dylib" + ); + + assert_eq!(results.ranges.len(), 3432); + assert_eq!(results.ranges[0].strings, [0]); + assert_eq!(results.ranges[0].unknown_uuid_index, 0); + assert_eq!(results.ranges[0].range_offset, 334248); + assert_eq!(results.ranges[0].range_size, 1); + + assert_eq!(results.signature, 1685283688); // hcsd + assert_eq!(results.major_version, 2); + assert_eq!(results.minor_version, 0); + assert_eq!(results.dsc_uuid, ""); + assert_eq!(results.number_ranges, 3432); + assert_eq!(results.number_uuids, 2250); + } + + #[test] + #[should_panic(expected = "Incomplete(Unknown)")] + fn test_bad_header() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push( + "tests/test_data/Bad Data/DSC/bad_header_version_1_522F6217CB113F8FB845C2A1B784C7C2", + ); + + let buffer = fs::read(test_path).unwrap(); + let (_, _) = SharedCacheStrings::parse_dsc(&buffer).unwrap(); + } + + #[test] + #[should_panic(expected = "Eof")] + fn test_bad_content() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push( + "tests/test_data/Bad Data/DSC/bad_content_version_1_522F6217CB113F8FB845C2A1B784C7C2", + ); + + let buffer = fs::read(test_path).unwrap(); + let (_, _) = SharedCacheStrings::parse_dsc(&buffer).unwrap(); + } + + #[test] + #[should_panic(expected = "Incomplete(Unknown)")] + fn test_bad_file() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Bad Data/DSC/badfile"); + + let buffer = fs::read(test_path).unwrap(); + let (_, _) = SharedCacheStrings::parse_dsc(&buffer).unwrap(); + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100755 index 0000000..662c8e9 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,98 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use nom::error::{ErrorKind, ParseError}; +use std::fmt; + +pub struct FirehoseError { + message: String, +} + +#[derive(Debug)] +pub struct CatalogProcessUUIDEntryError { + pub(crate) message: String, +} + +#[derive(Debug)] +pub struct FirehoseFormatterError { + pub(crate) message: String, +} + +impl ParseError<&[u8]> for FirehoseError { + fn from_error_kind(input: &[u8], kind: ErrorKind) -> Self { + let message = format!("Failed to parse firehose data: {:?}: {:?}", kind, input); + FirehoseError { message } + } + + fn append(input: &[u8], kind: ErrorKind, other: Self) -> Self { + let message = format!( + "Failed to parse firehose data: {} {:?}: {:?}", + other.message, kind, input + ); + FirehoseError { message } + } +} + +impl ParseError<&[u8]> for CatalogProcessUUIDEntryError { + fn from_error_kind(input: &[u8], kind: ErrorKind) -> Self { + let message = format!( + "Failed to parse Catalog Process UUID Entry metadata: {:?}: {:?}", + kind, input + ); + CatalogProcessUUIDEntryError { message } + } + + fn append(input: &[u8], kind: ErrorKind, other: Self) -> Self { + let message = format!( + "Failed to parse Catalog Process UUID Entry metadata: {} {:?}: {:?}", + other.message, kind, input + ); + CatalogProcessUUIDEntryError { message } + } +} + +impl ParseError<&[u8]> for FirehoseFormatterError { + fn from_error_kind(input: &[u8], kind: ErrorKind) -> Self { + let message = format!("Unknown firehose formatter flag: {:?}: {:?}", kind, input); + FirehoseFormatterError { message } + } + + fn append(input: &[u8], kind: ErrorKind, other: Self) -> Self { + let message = format!( + "Unknown firehose formatter flag: {} {:?}: {:?}", + other.message, kind, input + ); + FirehoseFormatterError { message } + } +} + +#[derive(Debug)] +pub enum ParserError { + Path, + Dir, + Tracev3Parse, + Read, + Timesync, + Dsc, + UUIDText, +} + +impl std::error::Error for ParserError {} + +impl fmt::Display for ParserError { + fn fmt<'a>(&self, f: &mut fmt::Formatter<'a>) -> fmt::Result { + match self { + ParserError::Path => write!(f, "Failed to open file path"), + ParserError::Dir => write!(f, "Failed to open directory path"), + ParserError::Tracev3Parse => write!(f, "Failed to parse tracev3 file"), + ParserError::Read => write!(f, "Failed to read file"), + ParserError::Timesync => write!(f, "Failed to parse timesync file"), + ParserError::Dsc => write!(f, "Failed to parse dsc file"), + ParserError::UUIDText => write!(f, "Failedto parse UUIDtext file"), + } + } +} diff --git a/src/header.rs b/src/header.rs new file mode 100755 index 0000000..6749e0a --- /dev/null +++ b/src/header.rs @@ -0,0 +1,255 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use std::{mem::size_of, str::from_utf8}; + +use log::warn; +use nom::{ + bytes::complete::take, + number::complete::{be_u128, le_u32, le_u64}, +}; + +#[derive(Debug, Clone)] +pub struct HeaderChunk { + pub chunk_tag: u32, + pub chunk_sub_tag: u32, + pub chunk_data_size: u64, + pub mach_time_numerator: u32, + pub mach_time_denominator: u32, + pub continous_time: u64, + pub unknown_time: u64, // possibly start time + pub unknown: u32, + pub bias_min: u32, + pub daylight_savings: u32, // 0 no DST, 1 DST + pub unknown_flags: u32, + pub sub_chunk_tag: u32, // 0x6100 + pub sub_chunk_data_size: u32, + pub sub_chunk_continous_time: u64, + pub sub_chunk_tag_2: u32, // 0x6101 + pub sub_chunk_tag_data_size_2: u32, + pub unknown_2: u32, + pub unknown_3: u32, + pub build_version_string: String, + pub hardware_model_string: String, + pub sub_chunk_tag_3: u32, // 0x6102 + pub sub_chunk_tag_data_size_3: u32, + pub boot_uuid: String, + pub logd_pid: u32, + pub logd_exit_status: u32, + pub sub_chunk_tag_4: u32, // 0x6103 + pub sub_chunk_tag_data_size_4: u32, + pub timezone_path: String, +} + +impl HeaderChunk { + /// Parse the Unified Log tracev3 header data + pub fn parse_header(data: &[u8]) -> nom::IResult<&[u8], HeaderChunk> { + let mut header_chunk = HeaderChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + mach_time_numerator: 0, + mach_time_denominator: 0, + continous_time: 0, + unknown_time: 0, + unknown: 0, + bias_min: 0, + daylight_savings: 0, + unknown_flags: 0, + sub_chunk_tag: 0, + sub_chunk_data_size: 0, + sub_chunk_continous_time: 0, + sub_chunk_tag_2: 0, + sub_chunk_tag_data_size_2: 0, + unknown_2: 0, + unknown_3: 0, + build_version_string: String::new(), + hardware_model_string: String::new(), + sub_chunk_tag_3: 0, + sub_chunk_tag_data_size_3: 0, + boot_uuid: String::new(), + logd_pid: 0, + logd_exit_status: 0, + sub_chunk_tag_4: 0, + sub_chunk_tag_data_size_4: 0, + timezone_path: String::new(), + }; + let (input, chunk_tag) = take(size_of::())(data)?; + let (input, chunk_sub_tag) = take(size_of::())(input)?; + let (input, chunk_data_size) = take(size_of::())(input)?; + let (input, mach_time_numerator) = take(size_of::())(input)?; + let (input, mach_time_denominator) = take(size_of::())(input)?; + let (input, continous_time) = take(size_of::())(input)?; + let (input, unknown_time) = take(size_of::())(input)?; + let (input, unknown) = take(size_of::())(input)?; + let (input, bias_min) = take(size_of::())(input)?; + let (input, daylight_savings) = take(size_of::())(input)?; + let (input, unknown_flags) = take(size_of::())(input)?; + let (input, sub_chunk_tag) = take(size_of::())(input)?; + let (input, sub_chunk_data_size) = take(size_of::())(input)?; + let (input, sub_chunk_continous_time) = take(size_of::())(input)?; + let (input, sub_chunk_tag_2) = take(size_of::())(input)?; + let (input, sub_chunk_tag_data_size_2) = take(size_of::())(input)?; + let (input, unknown_2) = take(size_of::())(input)?; + let (input, unknown_3) = take(size_of::())(input)?; + let (input, build_version_string) = take(size_of::())(input)?; + + let hardware_model_size: u8 = 32; + let (input, hardware_model_string) = take(hardware_model_size)(input)?; + let (input, sub_chunk_tag_3) = take(size_of::())(input)?; + let (input, sub_chunk_tag_data_size_3) = take(size_of::())(input)?; + let (input, boot_uuid) = take(size_of::())(input)?; + let (input, logd_pid) = take(size_of::())(input)?; + let (input, logd_exit_status) = take(size_of::())(input)?; + let (input, sub_chunk_tag_4) = take(size_of::())(input)?; + let (input, sub_chunk_tag_data_size_4) = take(size_of::())(input)?; + + let timezone_path_size: u8 = 48; + let (input, timezone_path) = take(timezone_path_size)(input)?; + + let (_, header_chunk_tag) = le_u32(chunk_tag)?; + let (_, header_chunk_sub_tag) = le_u32(chunk_sub_tag)?; + let (_, header_chunk_data_size) = le_u64(chunk_data_size)?; + let (_, header_mach_time_numerator) = le_u32(mach_time_numerator)?; + let (_, header_mach_time_denominator) = le_u32(mach_time_denominator)?; + let (_, header_continous_time) = le_u64(continous_time)?; + let (_, header_unknown_time) = le_u64(unknown_time)?; + let (_, header_unknown) = le_u32(unknown)?; + let (_, header_bias_min) = le_u32(bias_min)?; + let (_, header_daylight_savings) = le_u32(daylight_savings)?; + let (_, header_unknown_flags) = le_u32(unknown_flags)?; + let (_, header_sub_chunk_tag) = le_u32(sub_chunk_tag)?; + let (_, header_sub_chunk_data_size) = le_u32(sub_chunk_data_size)?; + let (_, header_sub_chunk_continous_time) = le_u64(sub_chunk_continous_time)?; + let (_, header_sub_chunk_tag_2) = le_u32(sub_chunk_tag_2)?; + let (_, header_sub_chunk_tag_data_size_2) = le_u32(sub_chunk_tag_data_size_2)?; + let (_, header_unknown_2) = le_u32(unknown_2)?; + let (_, header_unknown_3) = le_u32(unknown_3)?; + let (_, header_sub_chunk_tag_3) = le_u32(sub_chunk_tag_3)?; + let (_, header_sub_chunk_tag_data_size_3) = le_u32(sub_chunk_tag_data_size_3)?; + let (_, header_logd_pid) = le_u32(logd_pid)?; + let (_, header_logd_exit_status) = le_u32(logd_exit_status)?; + let (_, header_sub_chunk_tag_4) = le_u32(sub_chunk_tag_4)?; + let (_, header_sub_chunk_tag_data_size_4) = le_u32(sub_chunk_tag_data_size_4)?; + + header_chunk.chunk_tag = header_chunk_tag; + header_chunk.chunk_sub_tag = header_chunk_sub_tag; + header_chunk.chunk_data_size = header_chunk_data_size; + header_chunk.mach_time_numerator = header_mach_time_numerator; + header_chunk.mach_time_denominator = header_mach_time_denominator; + header_chunk.continous_time = header_continous_time; + header_chunk.unknown_time = header_unknown_time; + header_chunk.unknown = header_unknown; + header_chunk.bias_min = header_bias_min; + header_chunk.daylight_savings = header_daylight_savings; + header_chunk.unknown_flags = header_unknown_flags; + header_chunk.sub_chunk_tag = header_sub_chunk_tag; + header_chunk.sub_chunk_data_size = header_sub_chunk_data_size; + header_chunk.sub_chunk_continous_time = header_sub_chunk_continous_time; + header_chunk.sub_chunk_tag_2 = header_sub_chunk_tag_2; + header_chunk.sub_chunk_tag_data_size_2 = header_sub_chunk_tag_data_size_2; + header_chunk.unknown_2 = header_unknown_2; + header_chunk.unknown_3 = header_unknown_3; + header_chunk.sub_chunk_tag_3 = header_sub_chunk_tag_3; + header_chunk.sub_chunk_tag_data_size_3 = header_sub_chunk_tag_data_size_3; + header_chunk.logd_pid = header_logd_pid; + header_chunk.logd_exit_status = header_logd_exit_status; + header_chunk.sub_chunk_tag_4 = header_sub_chunk_tag_4; + header_chunk.sub_chunk_tag_data_size_4 = header_sub_chunk_tag_data_size_4; + + let path_data = from_utf8(timezone_path); + match path_data { + Ok(results) => header_chunk.timezone_path = results.trim_end_matches('\0').to_string(), + Err(err) => warn!( + "[macos-unifiedlogs] Failed to get timezone path from header: {:?}", + err + ), + } + + let build_version = from_utf8(build_version_string); + match build_version { + Ok(results) => { + header_chunk.build_version_string = results.trim_end_matches('\0').to_string() + } + Err(err) => warn!( + "[macos-unifiedlogs] Failed to get build version from header: {:?}", + err + ), + } + + let hardware_info = from_utf8(hardware_model_string); + match hardware_info { + Ok(results) => { + header_chunk.hardware_model_string = results.trim_end_matches('\0').to_string() + } + Err(err) => warn!( + "[macos-unifiedlogs] Failed to get hardware info from header: {:?}", + err + ), + } + + let (_, boot_uuid_be) = be_u128(boot_uuid)?; + header_chunk.boot_uuid = format!("{:X}", boot_uuid_be); + + Ok((input, header_chunk)) + } +} + +#[cfg(test)] +mod tests { + + use super::HeaderChunk; + + #[test] + fn test_detect_preamble() { + let test_chunk_header = [ + 0, 16, 0, 0, 17, 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 15, 105, + 217, 162, 204, 126, 0, 0, 48, 215, 18, 98, 0, 0, 0, 0, 203, 138, 9, 0, 44, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 97, 0, 0, 8, 0, 0, 0, 6, 112, 124, 198, 169, 153, 1, 0, 1, 97, + 0, 0, 56, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 50, 49, 65, 53, 53, 57, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 77, 97, 99, 66, 111, 111, 107, 80, 114, 111, 49, 54, 44, 49, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 97, 0, 0, 24, 0, 0, 0, 195, 32, 184, 206, 151, + 250, 77, 165, 159, 49, 125, 57, 46, 56, 156, 234, 85, 0, 0, 0, 0, 0, 0, 0, 3, 97, 0, 0, + 48, 0, 0, 0, 47, 118, 97, 114, 47, 100, 98, 47, 116, 105, 109, 101, 122, 111, 110, 101, + 47, 122, 111, 110, 101, 105, 110, 102, 111, 47, 65, 109, 101, 114, 105, 99, 97, 47, 78, + 101, 119, 95, 89, 111, 114, 107, 0, 0, 0, 0, 0, 0, + ]; + + let (_, header_data) = HeaderChunk::parse_header(&test_chunk_header).unwrap(); + + assert_eq!(header_data.chunk_tag, 0x1000); + assert_eq!(header_data.chunk_sub_tag, 0x11); + assert_eq!(header_data.mach_time_numerator, 1); + assert_eq!(header_data.mach_time_denominator, 1); + assert_eq!(header_data.continous_time, 139417370585359); + assert_eq!(header_data.unknown_time, 1645401904); + assert_eq!(header_data.unknown, 625355); + assert_eq!(header_data.bias_min, 300); + assert_eq!(header_data.daylight_savings, 0); + assert_eq!(header_data.unknown_flags, 1); + assert_eq!(header_data.sub_chunk_tag, 24832); + assert_eq!(header_data.sub_chunk_data_size, 8); + assert_eq!(header_data.sub_chunk_continous_time, 450429435277318); + assert_eq!(header_data.sub_chunk_tag_2, 24833); + assert_eq!(header_data.sub_chunk_tag_data_size_2, 56); + assert_eq!(header_data.unknown_2, 7); + assert_eq!(header_data.unknown_3, 8); + assert_eq!(header_data.build_version_string, "21A559"); + assert_eq!(header_data.hardware_model_string, "MacBookPro16,1"); + assert_eq!(header_data.sub_chunk_tag_3, 24834); + assert_eq!(header_data.sub_chunk_tag_data_size_3, 24); + assert_eq!(header_data.boot_uuid, "C320B8CE97FA4DA59F317D392E389CEA"); + assert_eq!(header_data.logd_pid, 85); + assert_eq!(header_data.logd_exit_status, 0); + assert_eq!(header_data.sub_chunk_tag_4, 24835); + assert_eq!(header_data.sub_chunk_tag_data_size_4, 48); + assert_eq!( + header_data.timezone_path, + "/var/db/timezone/zoneinfo/America/New_York" + ); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100755 index 0000000..1c750cd --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,46 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +#![forbid(unsafe_code)] +#![warn( + clippy::all, + clippy::doc_markdown, + clippy::needless_continue, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::fn_params_excessive_bools, + clippy::inefficient_to_string, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + rust_2018_idioms, + future_incompatible, +)] +#![deny( + clippy::cast_lossless, + //clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_ptr_alignment, + //clippy::cast_sign_loss, + clippy::char_lit_as_u8, + clippy::checked_conversions, + clippy::unnecessary_cast +)] +mod catalog; +mod chunks; +mod chunkset; +pub mod dsc; +mod error; +mod header; +mod message; +pub mod parser; +mod preamble; +pub mod timesync; +pub mod unified_log; +mod util; +pub mod uuidtext; diff --git a/src/message.rs b/src/message.rs new file mode 100755 index 0000000..0865221 --- /dev/null +++ b/src/message.rs @@ -0,0 +1,1441 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use std::mem::size_of; + +use crate::chunks::firehose::firehose_log::FirehoseItemInfo; +use log::{error, info, warn}; +use nom::branch::alt; +use nom::bytes::complete::{is_a, is_not, take, take_until}; +use nom::character::complete::digit0; +use regex::Regex; + +struct FormatAndMessage { + formatter: String, + message: String, +} + +const FLOAT_TYPES: [&str; 6] = ["f", "F", "e", "E", "g", "G"]; +const INT_TYPES: [&str; 4] = ["d", "D", "i", "u"]; +const HEX_TYPES: [&str; 5] = ["x", "X", "a", "A", "p"]; +const OCTAL_TYPES: [&str; 2] = ["o", "O"]; +const ERROR_TYPES: [&str; 1] = ["m"]; +const STRING_TYPES: [&str; 6] = ["c", "s", "@", "S", "C", "P"]; + +/// Format the Unified Log message entry based on the parsed log items. Formatting follows the C lang prinf formatting process +pub fn format_firehose_log_message( + format_string: String, + item_message: &Vec, + message_re: &Regex, +) -> String { + let mut log_message = format_string; + let mut format_and_message_vec: Vec = Vec::new(); + info!("Unified log base message: {:?}", log_message); + info!("Unified log entry strings: {:?}", item_message); + + // Some log entries may be completely empty (no format string or message data) + /* + tp 1976 + 32: log default (shared_cache, has_subsystem) + thread: 0000000000000d8f + time: +56.919s + walltime: 1642303846 - 2022-01-15 19:30:46 (Saturday) + location: pc:0x1bd34bda fmt:0x1bde2be0 + image uuid: 4CA1B500-20EF-3E30-B63B-3E3579524A7F + image path: /System/Library/PrivateFrameworks/TelephonyUtilities.framework/Versions/A/TelephonyUtilities + format: + subsystem: 156 com.apple.calls.telephonyutilities.Default + */ + if log_message.is_empty() && item_message.is_empty() { + return String::new(); + } + if log_message.is_empty() { + return item_message[0].message_strings.to_owned(); + } + let results = message_re.find_iter(&log_message); + + let mut item_index = 0; + for formatter in results { + // Skip literal "% " values + if formatter.as_str().starts_with("% ") { + continue; + } + + let mut format_and_message = FormatAndMessage { + formatter: String::new(), + message: String::new(), + }; + + // %% is literal % + if formatter.as_str() == "%%" { + format_and_message.formatter = formatter.as_str().to_string(); + format_and_message.message = String::from("%"); + format_and_message_vec.push(format_and_message); + continue; + } + + // Sometimes the log message does not have all of the message strings + // Apple labels them: "" + if item_index >= item_message.len() { + format_and_message.formatter = formatter.as_str().to_string(); + format_and_message.message = String::from(""); + format_and_message_vec.push(format_and_message); + continue; + } + let mut formatted_log_message = item_message[item_index].message_strings.to_owned(); + let formatter_string = formatter.as_str(); + + // If the formatter does not have a type then the entry is the literal foramt + // Ex: RDAlarmNotificationConsumer {identifier: %{public}%@ currentSet: %@, count: %{public}%d} + // -> RDAlarmNotificationConsumer {identifier: {public} allowedSet: , count {public}0} + if formatter_string.starts_with("%{") && formatter_string.ends_with('}') { + format_and_message.formatter = formatter_string.to_string(); + formatter_string.to_string().remove(0); + format_and_message.message = formatter_string.to_string(); + format_and_message_vec.push(format_and_message); + continue; + } + + let private_strings = [0x1, 0x21, 0x31, 0x41]; + let private_number = 0x1; + let private_message = 0x8000; + if formatter_string.starts_with("%{") { + // If item type is [0x1, 0x21, 0x31, 0x41] and the value is zero. Its appears to be a private string + /* + 0x31 (object type) example below + tp 16 + 413: log default (shared_cache, has_subsystem) + pubdata: + 00000000: 04 00 04 02 50 f7 cf 2e ea ae 00 00 00 00 00 00 ....P........... + 00000010: 00 00 00 00 10 00 85 01 1a 74 bf 2e 0d 00 03 20 .........t..... + 00000020: 22 04 00 00 02 00 41 04 00 00 00 00 42 04 02 00 ".....A.....B... + 00000030: 56 00 22 04 58 00 04 00 12 04 10 00 00 00 32 04 V.".X.........2. + 00000040: 5c 00 10 00 01 04 00 00 00 00 02 04 4f c0 00 00 \...........O... + 00000050: 12 04 10 00 00 00 31 04 00 00 00 00 42 04 6c 00 ......1.....B.l. + 00000060: 39 00 02 04 01 00 00 00 02 04 43 03 00 00 02 04 9.........C..... + 00000070: 00 00 00 00 02 04 00 00 00 00 02 04 00 00 00 00 ................ + 00000080: 02 04 12 00 00 00 22 04 a5 00 04 00 02 04 00 00 ......"......... + 00000090: 00 00 02 04 12 00 00 00 02 04 00 00 00 00 02 04 ................ + 000000a0: 0f 00 00 00 02 04 00 00 00 00 02 04 28 00 00 00 ............(... + 000000b0: 02 08 2b 23 00 00 00 00 00 00 02 08 ad 03 00 00 ..+#............ + 000000c0: 00 00 00 00 02 08 08 00 00 00 00 00 00 00 02 08 ................ + 000000d0: 08 00 00 00 00 00 00 00 02 04 00 00 00 00 02 04 ................ + 000000e0: 0a 00 00 00 02 08 00 00 00 00 00 00 00 00 02 04 ................ + 000000f0: 00 00 00 00 39 00 73 74 72 65 61 6d 2c 20 62 75 ....9.stream, bu + 00000100: 6e 64 6c 65 20 69 64 3a 20 74 72 75 73 74 64 2c ndle id: trustd, + 00000110: 20 70 69 64 3a 20 31 35 38 2c 20 74 72 61 66 66 pid: 158, traff + 00000120: 69 63 20 63 6c 61 73 73 3a 20 31 30 30 2c 20 74 ic class: 100, t + 00000130: 6c 73 2c 20 69 6e 64 65 66 69 6e 69 74 65 2c 20 ls, indefinite, + 00000140: 6e 6f 20 63 65 6c 6c 75 6c 61 72 00 39 2e 31 00 no cellular.9.1. + 00000150: 11 5c 75 bd e7 7e 40 c2 ba cf 46 cc b6 32 da 2c .\u..~@...F..2., + 00000160: 73 61 74 69 73 66 69 65 64 20 28 50 61 74 68 20 satisfied (Path + 00000170: 69 73 20 73 61 74 69 73 66 69 65 64 29 2c 20 69 is satisfied), i + 00000180: 6e 74 65 72 66 61 63 65 3a 20 65 6e 30 2c 20 69 nterface: en0, i + 00000190: 70 76 34 2c 20 64 6e 73 00 54 43 50 00 pv4, dns.TCP. thread: 000000000000aeea + time: +68.719s + walltime: 1640404673 - 2021-12-24 22:57:53 (Friday) + location: pc:0x2ebf741a fmt:0x2ecff750 + image uuid: E185D902-AC7F-3044-87C0-AE2887C59CE7 + image path: /usr/lib/libnetwork.dylib + format: [%{public}s %{private}@ %{public}@] cancelled + [%s %{uuid_t}.16P %{private,network:in_addr}d.%d<->%{private,network:sockaddr}.*P] + Connected Path: %@ + Duration: %u.%03us, DNS @%u.%03us took %u.%03us, %{public}s @%u.%03us took %u.%03us, TLS took %u.%03us + bytes in/out: %llu/%llu, packets in/out: %llu/%llu, rtt: %u.%03us, retransmitted packets: %llu, out-of-order packets: %u + subsystem: 13 com.apple.network. + + [9 stream, bundle id: trustd, pid: 158, traffic class: 100, tls, indefinite, no cellular] cancelled + [9.1 115C75BD-E77E-40C2-BACF-46CCB632DA2C .49231<->] + Connected Path: satisfied (Path is satisfied), interface: en0, ipv4, dns + Duration: 1.835s, DNS @0.000s took 0.018s, TCP @0.018s took 0.015s, TLS took 0.040s + bytes in/out: 9003/941, packets in/out: 8/8, rtt: 0.010s, retransmitted packets: 0, out-of-order packets: 0 + */ + if private_strings.contains(&item_message[item_index].item_type) + && item_message[item_index].message_strings.is_empty() + && item_message[item_index].item_size == 0 + || (item_message[item_index].item_type == private_number + && item_message[item_index].item_size == private_message) + { + formatted_log_message = String::from(""); + } else { + let results = parse_type_formatter( + formatter_string, + item_message, + &item_message[item_index].item_type, + item_index, + ); + match results { + Ok((_, formatted_message)) => formatted_log_message = formatted_message, + Err(err) => warn!( + "Failed to format message type ex: public/private: {:?}", + err + ), + } + } + } else { + // If item type is [0x1, 0x21, 0x31, 0x41] and the size is zero (or 0x8000 for 0x1). Its appears to be a literal string + /* + 0x1 (number type) example below + tp 456 + 54: log default (main_exe) + pubdata: + 00000000: 04 00 02 00 d8 07 90 00 00 00 00 00 00 00 00 00 ................ + 00000010: 64 54 af 0a 00 00 1e 00 9c 00 89 00 01 04 01 04 dT.............. + 00000020: 00 00 00 00 01 04 00 00 00 00 01 04 00 00 00 00 ................ + 00000030: 01 04 00 00 00 00 ...... thread: 0000000000000000 + time: +0.179s + walltime: 1642303789 - 2022-01-15 19:29:49 (Saturday) + location: pc:0x89009c fmt:0x9007d8 + image uuid: ABC69550-60C2-34FE-B307-C24A8C39309C + image path: /kernel + format: kext submap [0x%lx - 0x%lx], kernel text [0x%lx - 0x%lx] + kext submap [0x - 0x], kernel text [0x - 0x] + */ + if private_strings.contains(&item_message[item_index].item_type) + && item_message[item_index].message_strings.is_empty() + && item_message[item_index].item_size == 0 + || (item_message[item_index].item_type == private_number + && item_message[item_index].item_size == private_message) + { + formatted_log_message = String::from(""); + } else { + let results = parse_formatter( + formatter_string, + item_message, + &item_message[item_index].item_type, + item_index, + ); + match results { + Ok((_, formatted_message)) => formatted_log_message = formatted_message, + Err(err) => warn!("[macos-unifiedlogs] Failed to format message: {:?}", err), + } + } + } + + let precision_items = [0x10, 0x12]; // dynamic precision item types? + // If the item message was a precision type increment to actual value + if precision_items.contains(&item_message[item_index].item_type) { + item_index += 1; + } + + // Also seen number type value 0 also used for dynamic width/precision value + let dynamic_precision_value = 0x0; + if (item_message[item_index].item_type == dynamic_precision_value + && item_message[item_index].item_size == 0) + && formatter_string.contains("%*") + { + item_index += 1; + } + + item_index += 1; + format_and_message.formatter = formatter.as_str().to_string(); + format_and_message.message = formatted_log_message; + format_and_message_vec.push(format_and_message); + } + + let mut log_message_vec: Vec = Vec::new(); + for values in format_and_message_vec { + // Split the values by printf formatter + // We have to do this instead of using replace because our replacement string may also contain a printf formatter + let message_results = log_message.split_once(&values.formatter); + match message_results { + Some((message_part, remaining_message)) => { + log_message_vec.push(message_part.to_string()); + log_message_vec.push(values.message); + log_message = remaining_message.to_string(); + } + None => error!( + "Failed to split log message ({}) by printf formatter: {}", + log_message, &values.formatter + ), + } + } + log_message_vec.push(log_message); + log_message_vec.join("") +} + +// Format strings are based on C printf formats. Parse format specification +fn parse_formatter<'a>( + formatter: &'a str, + message_value: &'a Vec, + item_type: &'a u8, + item_index: usize, +) -> nom::IResult<&'a str, String> { + let mut index = item_index; + + let precision_items = [0x10, 0x12]; + let mut precision_value = 0; + if precision_items.contains(item_type) { + precision_value = message_value[index].item_size as usize; + index += 1; + } + + let mut message = message_value[index].message_strings.to_owned(); + + let number_item_type: Vec = vec![0x0, 0x1, 0x2]; + + // If the message formatter is expects a string/character and the message string is a number type + // Try to convert to a character/string + if formatter.to_lowercase().ends_with('c') + && number_item_type.contains(&message_value[index].item_type) + { + let char_results = message_value[index].message_strings.parse::(); + match char_results { + Ok(char_message) => message = (char_message as u8 as char).to_string(), + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to parse number item to char string: {:?}", + err + ); + return Ok(( + "", + String::from("Failed to parse number item to char string"), + )); + } + } + } + + let mut left_justify = false; + //let mut space_value = false; + let mut hashtag = false; + let mut pad_zero = false; + let mut plus_minus = false; + let mut width_index = 1; + //let mut has_apostrophe = false; + for (index, format_values) in formatter.chars().enumerate() { + if index == 0 { + continue; + } + + match format_values { + '-' => left_justify = true, + '+' => plus_minus = true, + //' ' => space_value = true, + '#' => hashtag = true, + '0' => pad_zero = true, + // '\'' => has_apostrophe = true, + _ => { + width_index = index; + break; + } + } + } + + let mut formatter_message = &formatter[width_index..]; + let (input, mut width) = digit0(formatter_message)?; + formatter_message = input; + let width_value; + + if formatter_message.starts_with('*') { + // Also seen number type value 0 used for dynamic width/precision value + let dynamic_precision_value = 0x0; + if item_type == &dynamic_precision_value && message_value[index].item_size == 0 { + precision_value = message_value[index].item_size as usize; + index += 1; + message = message_value[index].message_strings.to_owned(); + } + + width_value = format!("{}", precision_value); + width = width_value.as_str(); + let (input, _) = take(size_of::())(formatter_message)?; + formatter_message = input; + } + + if formatter_message.starts_with('.') { + let (input, _) = is_a(".")(formatter_message)?; + let (input, precision_data) = is_not("hljzZtqLdDiuUoOcCxXfFeEgGaASspPn%@")(input)?; + if precision_data != "*" { + let precision_results = precision_data.parse::(); + match precision_results { + Ok(value) => precision_value = value, + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse format precision value: {:?}", + err + ), + } + } else if precision_value != 0 { + // For dynamic length use the length of the message string + precision_value = message_value.len(); + } + formatter_message = input; + } + + // Get Length data if it exists or get the type format + let (input, length_data) = + alt((is_a("hlwIztq"), is_a("cmCdiouxXeEfgGaAnpsSZP@")))(formatter_message)?; + formatter_message = input; + + let mut type_data = length_data; + let length_values = vec!["h", "hh", "l", "ll", "w", "I", "z", "t", "q"]; + if length_values.contains(&length_data) { + let (_, type_format) = is_a("cmCdiouxXeEfgGaAnpsSZP@")(formatter_message)?; + type_data = type_format; + } + + // Error types map error code to error message string. Currently not mapping to error message string + // Ex: open on %s: %m + // "open on /var/folders: No such file or directory" + // "No such file or directory" is error code 2 + if ERROR_TYPES.contains(&type_data) { + message = format!("Error code: {}", message); + return Ok(("", message)); + } + + if !width.is_empty() { + let mut width_value = 0; + let width_results = width.parse::(); + match width_results { + Ok(value) => width_value = value, + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse format width value: {:?}", + err + ), + } + if pad_zero { + // Pad using zeros instead of spaces + if left_justify { + message = format_alignment_left( + message, + width_value, + precision_value, + type_data, + plus_minus, + hashtag, + ) + } else { + message = format_alignment_right( + message, + width_value, + precision_value, + type_data, + plus_minus, + hashtag, + ) + } + } else { + // Pad spaces instead of zeros + if left_justify { + message = format_alignment_left_space( + message, + width_value, + precision_value, + type_data, + plus_minus, + hashtag, + ) + } else { + message = format_alignment_right_space( + message, + width_value, + precision_value, + type_data, + plus_minus, + hashtag, + ) + } + } + } else if left_justify { + message = format_left(message, precision_value, type_data, plus_minus, hashtag) + } else { + message = format_right(message, precision_value, type_data, plus_minus, hashtag); + } + + Ok(("", message)) +} + +// Function to parse formatters containing types. Ex: %{errno}d, %{public}s, %{private}s, %{sensitive} +fn parse_type_formatter<'a>( + formatter: &'a str, + message_value: &'a Vec, + item_type: &'a u8, + item_index: usize, +) -> nom::IResult<&'a str, String> { + let (format, format_type) = take_until("}")(formatter)?; + + let (_, mut message) = parse_formatter(format, message_value, item_type, item_index)?; + if format_type.contains("signpost") { + let (_, signpost_message) = parse_signpost_format(format_type)?; + message = format!("{} ({})", message, signpost_message); + } + Ok(("", message)) +} + +// Try to parse additional signpost metadata. +// Ex: %{public,signpost.description:attribute}@ +// %{public,signpost.telemetry:number1,name=SOSSignpostNameSOSCCCopyApplicantPeerInfo}d +fn parse_signpost_format(signpost_format: &str) -> nom::IResult<&str, String> { + let mut signpost_message; + let (signpost_value, _) = is_a("%{")(signpost_format)?; + + if signpost_format.starts_with("%{sign") { + let signpost_vec: Vec<&str> = signpost_value.split(',').collect(); + signpost_message = signpost_vec[0].to_string(); + } else { + let signpost_vec: Vec<&str> = signpost_value.split(',').collect(); + signpost_message = signpost_vec[1].to_string(); + signpost_message = signpost_message.trim().to_string(); + } + Ok(("", signpost_message)) +} + +// Align the message to the left and pad using zeros instead of spaces +fn format_alignment_left( + format_message: String, + format_width: usize, + format_precision: usize, + type_data: &str, + plus_minus: bool, + hashtag: bool, +) -> String { + let mut message = format_message; + let mut precision_value = format_precision; + let mut plus_option = String::new(); + + let mut adjust_width = 0; + if plus_minus { + plus_option = String::from("+"); + adjust_width = 1; + } + + if FLOAT_TYPES.contains(&type_data) { + let float_message = parse_float(message); + if precision_value == 0 { + let message_float = float_message.to_string(); + let float_precision: Vec<&str> = message_float.split('.').collect(); + if float_precision.len() == 2 { + precision_value = float_precision[1].len(); + } + } + message = format!( + "{plus_symbol}{:0 String { + let mut message = format_message; + let mut precision_value = format_precision; + let mut plus_option = String::new(); + + let mut adjust_width = 0; + if plus_minus { + plus_option = String::from("+"); + adjust_width = 1; + } + + if FLOAT_TYPES.contains(&type_data) { + let float_message = parse_float(message); + if precision_value == 0 { + let message_float = float_message.to_string(); + let float_precision: Vec<&str> = message_float.split('.').collect(); + if float_precision.len() == 2 { + precision_value = float_precision[1].len(); + } + } + message = format!( + "{plus_symbol}{:0>width$.precision$}", + float_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if INT_TYPES.contains(&type_data) { + let int_message = parse_int(message); + message = format!( + "{plus_symbol}{:0>width$.precision$}", + int_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if STRING_TYPES.contains(&type_data) { + if precision_value == 0 { + precision_value = message.len() + } + message = format!( + "{plus_symbol}{:0>width$.precision$}", + message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if HEX_TYPES.contains(&type_data) { + let hex_message = parse_int(message); + if hashtag { + message = format!( + "{plus_symbol}{:0>#width$.precision$X}", + hex_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else { + message = format!( + "{plus_symbol}{:0>width$.precision$X}", + hex_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } + } else if OCTAL_TYPES.contains(&type_data) { + let octal_message = parse_int(message); + if hashtag { + message = format!( + "{plus_symbol}{:0>#width$.precision$o}", + octal_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else { + message = format!( + "{plus_symbol}{:0>width$.precision$o}", + octal_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } + } + message +} + +// Align the message to the left and pad using spaces +fn format_alignment_left_space( + format_message: String, + format_width: usize, + format_precision: usize, + type_data: &str, + plus_minus: bool, + hashtag: bool, +) -> String { + let mut message = format_message; + let mut precision_value = format_precision; + let mut plus_option = String::new(); + + let mut adjust_width = 0; + if plus_minus { + plus_option = String::from("+"); + adjust_width = 1; + } + + if FLOAT_TYPES.contains(&type_data) { + let float_message = parse_float(message); + if precision_value == 0 { + let message_float = float_message.to_string(); + let float_precision: Vec<&str> = message_float.split('.').collect(); + if float_precision.len() == 2 { + precision_value = float_precision[1].len(); + } + } + message = format!( + "{plus_symbol}{: String { + let mut message = format_message; + let mut precision_value = format_precision; + let mut plus_option = String::new(); + + let mut adjust_width = 0; + if plus_minus { + plus_option = String::from("+"); + adjust_width = 1; + } + + if FLOAT_TYPES.contains(&type_data) { + let float_message = parse_float(message); + if precision_value == 0 { + let message_float = float_message.to_string(); + let float_precision: Vec<&str> = message_float.split('.').collect(); + if float_precision.len() == 2 { + precision_value = float_precision[1].len(); + } + } + message = format!( + "{plus_symbol}{:>width$.precision$}", + float_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if INT_TYPES.contains(&type_data) { + let int_message = parse_int(message); + message = format!( + "{plus_symbol}{:>width$.precision$}", + int_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if STRING_TYPES.contains(&type_data) { + if precision_value == 0 { + precision_value = message.len() + } + message = format!( + "{plus_symbol}{:>width$.precision$}", + message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if HEX_TYPES.contains(&type_data) { + let hex_message = parse_int(message); + if hashtag { + message = format!( + "{plus_symbol}{:>#width$.precision$X}", + hex_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else { + message = format!( + "{plus_symbol}{:>width$.precision$X}", + hex_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } + } else if OCTAL_TYPES.contains(&type_data) { + let octal_message = parse_int(message); + if hashtag { + message = format!( + "{plus_symbol}{:>#width$.precision$o}", + octal_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else { + message = format!( + "{plus_symbol}{:>width$.precision$o}", + octal_message, + width = format_width - adjust_width, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } + } + message +} + +// Align the message to the left +fn format_left( + format_message: String, + format_precision: usize, + type_data: &str, + plus_minus: bool, + hashtag: bool, +) -> String { + let mut message = format_message; + let mut precision_value = format_precision; + let mut plus_option = String::new(); + + if plus_minus { + plus_option = String::from("+"); + } + + if FLOAT_TYPES.contains(&type_data) { + let float_message = parse_float(message); + if precision_value == 0 { + let message_float = float_message.to_string(); + let float_precision: Vec<&str> = message_float.split('.').collect(); + if float_precision.len() == 2 { + precision_value = float_precision[1].len(); + } + } + + message = format!( + "{plus_symbol}{:<.precision$}", + float_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if INT_TYPES.contains(&type_data) { + let int_message = parse_int(message); + message = format!( + "{plus_symbol}{:<.precision$}", + int_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if STRING_TYPES.contains(&type_data) { + if precision_value == 0 { + precision_value = message.len() + } + message = format!( + "{plus_symbol}{:<.precision$}", + message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if HEX_TYPES.contains(&type_data) { + let hex_message = parse_int(message); + if hashtag { + message = format!( + "{plus_symbol}{:<#.precision$X}", + hex_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else { + message = format!( + "{plus_symbol}{:<.precision$X}", + hex_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } + } else if OCTAL_TYPES.contains(&type_data) { + let octal_message = parse_int(message); + if hashtag { + message = format!( + "{plus_symbol}{:<#.precision$o}", + octal_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else { + message = format!( + "{plus_symbol}{:<.precision$o}", + octal_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } + } + message +} + +// Align the message to the right (default) +fn format_right( + format_message: String, + format_precision: usize, + type_data: &str, + plus_minus: bool, + hashtag: bool, +) -> String { + let mut message = format_message; + let mut precision_value = format_precision; + let mut plus_option = String::new(); + + if plus_minus { + plus_option = String::from("+"); + } + + if FLOAT_TYPES.contains(&type_data) { + let float_message = parse_float(message); + if precision_value == 0 { + let message_float = float_message.to_string(); + let float_precision: Vec<&str> = message_float.split('.').collect(); + if float_precision.len() == 2 { + precision_value = float_precision[1].len(); + } + } + + message = format!( + "{plus_symbol}{:>.precision$}", + float_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if INT_TYPES.contains(&type_data) { + let int_message = parse_int(message); + message = format!( + "{plus_symbol}{:>.precision$}", + int_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if STRING_TYPES.contains(&type_data) { + if precision_value == 0 { + precision_value = message.len() + } + message = format!( + "{plus_symbol}{:>.precision$}", + message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else if HEX_TYPES.contains(&type_data) { + let hex_message = parse_int(message); + if hashtag { + message = format!( + "{plus_symbol}{:>#.precision$X}", + hex_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } else { + message = format!( + "{plus_symbol}{:>.precision$X}", + hex_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } + } else if OCTAL_TYPES.contains(&type_data) { + let octal_message = parse_int(message); + message = format!( + "{plus_symbol}{:>#.precision$o}", + octal_message, + precision = precision_value as usize, + plus_symbol = plus_option + ); + } + message +} + +// Parse the float string log message to float value +fn parse_float(message: String) -> f64 { + let byte_results = message.parse::(); + match byte_results { + Ok(bytes) => return f64::from_bits(bytes as u64), + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse float log message value: {}, err: {:?}", + message, err + ), + } + f64::from_bits(0) +} + +// Parse the int string log message to int value +fn parse_int(message: String) -> i64 { + let int_results = message.parse::(); + match int_results { + Ok(message) => return message, + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse int log message value: {}, err: {:?}", + message, err + ), + } + 0 +} + +#[cfg(test)] +mod tests { + use crate::chunks::firehose::firehose_log::FirehoseItemInfo; + use crate::message::{ + format_alignment_left, format_alignment_left_space, format_alignment_right, + format_alignment_right_space, format_firehose_log_message, format_left, format_right, + parse_float, parse_formatter, parse_int, parse_signpost_format, parse_type_formatter, + }; + use regex::Regex; + + #[test] + fn test_format_firehose_log_message() { + let test_data = String::from("opendirectoryd (build %{public}s) launched..."); + let mut item_message: Vec = Vec::new(); + item_message.push(FirehoseItemInfo { + message_strings: String::from("796.100"), + item_type: 34, + item_size: 0, + }); + let message_re = Regex::new(r"(%(?:(?:\{[^}]+}?)(?:[-+0#]{0,5})(?:\d+|\*)?(?:\.(?:\d+|\*))?(?:h|hh|l|ll|w|I|z|t|q|I32|I64)?[cmCdiouxXeEfgGaAnpsSZP@%}]|(?:[-+0 #]{0,5})(?:\d+|\*)?(?:\.(?:\d+|\*))?(?:h|hh|l||q|t|ll|w|I|z|I32|I64)?[cmCdiouxXeEfgGaAnpsSZP@%]))").unwrap(); + + let log_string = format_firehose_log_message(test_data, &item_message, &message_re); + assert_eq!(log_string, "opendirectoryd (build 796.100) launched...") + } + + #[test] + fn test_parse_formatter() { + let test_format = "%+04d"; + let mut test_message = Vec::new(); + + let test_data = FirehoseItemInfo { + message_strings: String::from("2"), + item_type: 2, + item_size: 2, + }; + test_message.push(test_data); + + let item_index = 0; + let (_, formatted_results) = parse_formatter( + test_format, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "+002"); + + let test_format = "%04d"; + let (_, formatted_results) = parse_formatter( + test_format, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "0002"); + + let test_format = "%#4x"; + let (_, formatted_results) = parse_formatter( + test_format, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, " 0x2"); + + let test_format = "%#04o"; + test_message[0].message_strings = String::from("100"); + let (_, formatted_results) = parse_formatter( + test_format, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "0o144"); + + let test_format = "%07o"; + let (_, formatted_results) = parse_formatter( + test_format, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "0000144"); + + let test_format = "%x"; + test_message[0].message_strings = String::from("10"); + let (_, formatted_results) = parse_formatter( + test_format, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "A"); + + let test_float = "%+09.4f"; + test_message[0].message_strings = String::from("4570111009880014848"); + let (_, formatted_results) = parse_formatter( + test_float, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "+000.0035"); + + let test_float = "%9.4f"; + let (_, formatted_results) = parse_formatter( + test_float, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, " 0.0035"); + + let test_float = "%-8.4f"; + let (_, formatted_results) = parse_formatter( + test_float, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "0.0035 "); + + let test_float = "%f"; + test_message[0].message_strings = String::from("4614286721111404799"); + let (_, formatted_results) = parse_formatter( + test_float, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "3.154944"); + + let test_int = "%d"; + test_message[0].message_strings = String::from("-248"); + let (_, formatted_results) = parse_formatter( + test_int, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "-248"); + + let test_float = "%f"; + test_message[0].message_strings = String::from("-4611686018427387904"); + let (_, formatted_results) = parse_formatter( + test_float, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "-2"); + + let test_float = "%f"; + test_message[0].message_strings = String::from("-4484628366119329180"); + let (_, formatted_results) = parse_formatter( + test_float, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "-650937839.633862"); + + let test_string = "%s"; + test_message[0].message_strings = String::from("The big red dog jumped over the crab"); + let (_, formatted_results) = parse_formatter( + test_string, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "The big red dog jumped over the crab"); + + let test_string = "%.2@"; + test_message[0].message_strings = String::from("aaabbbb"); + let (_, formatted_results) = parse_formatter( + test_string, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "aa"); + + let test_string = "%*s"; + test_message[0].item_size = 10; + test_message[0].item_type = 0x12; + let test_data2 = FirehoseItemInfo { + message_strings: String::from("hi"), + item_type: 2, + item_size: 2, + }; + test_message.push(test_data2); + let (_, formatted_results) = parse_formatter( + test_string, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, " hi"); + } + + #[test] + fn test_parse_type_formatter() { + let mut test_format = "%{public}s"; + let mut test_message = Vec::new(); + + let mut test_data = FirehoseItemInfo { + message_strings: String::from("test"), + item_type: 2, + item_size: 4, + }; + test_message.push(test_data); + + let item_index = 0; + let (_, formatted_results) = parse_type_formatter( + test_format, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "test"); + + test_format = "%{public, signpost.description:begin_time}llu"; + let mut test_message = Vec::new(); + + test_data = FirehoseItemInfo { + message_strings: String::from("1"), + item_type: 2, + item_size: 4, + }; + test_message.push(test_data); + + let item_index = 0; + let (_, formatted_results) = parse_type_formatter( + test_format, + &test_message, + &test_message[0].item_type, + item_index, + ) + .unwrap(); + assert_eq!(formatted_results, "1 (signpost.description:begin_time)"); + } + + #[test] + fn test_parse_signpost_format() { + let test_format = "%{public, signpost.description:begin_time"; + let (_, results) = parse_signpost_format(test_format).unwrap(); + assert_eq!(results, "signpost.description:begin_time"); + } + + #[test] + fn test_format_alignment_left() { + let test_type = "d"; + let test_width = 4; + let test_precision = 0; + let test_format = String::from("2"); + let plus_minus = false; + let hashtag = false; + let formatted_results = format_alignment_left( + test_format, + test_width, + test_precision, + &test_type, + plus_minus, + hashtag, + ); + assert_eq!(formatted_results, "2000"); + } + + #[test] + fn test_format_alignment_right() { + let test_type = "d"; + let test_width = 4; + let test_precision = 0; + let test_format = String::from("2"); + let plus_minus = false; + let hashtag = false; + let formatted_results = format_alignment_right( + test_format, + test_width, + test_precision, + &test_type, + plus_minus, + hashtag, + ); + assert_eq!(formatted_results, "0002"); + } + + #[test] + fn test_format_alignment_left_space() { + let test_type = "d"; + let test_width = 4; + let test_precision = 0; + let test_format = String::from("2"); + let plus_minus = false; + let hashtag = false; + let formatted_results = format_alignment_left_space( + test_format, + test_width, + test_precision, + &test_type, + plus_minus, + hashtag, + ); + assert_eq!(formatted_results, "2 "); + } + + #[test] + fn test_format_alignment_right_space() { + let test_type = "d"; + let test_width = 4; + let test_precision = 0; + let test_format = String::from("2"); + let plus_minus = false; + let hashtag = false; + let formatted_results = format_alignment_right_space( + test_format, + test_width, + test_precision, + &test_type, + plus_minus, + hashtag, + ); + assert_eq!(formatted_results, " 2"); + } + + #[test] + fn test_format_left() { + let test_type = "d"; + let test_precision = 0; + let test_format = String::from("2"); + let plus_minus = false; + let hashtag = false; + let formatted_results = + format_left(test_format, test_precision, &test_type, plus_minus, hashtag); + assert_eq!(formatted_results, "2"); + } + + #[test] + fn test_format_right() { + let test_type = "d"; + let test_precision = 0; + let test_format = String::from("2"); + let plus_minus = false; + let hashtag = false; + let formatted_results = + format_right(test_format, test_precision, &test_type, plus_minus, hashtag); + assert_eq!(formatted_results, "2"); + } + + #[test] + fn test_parse_float() { + let value = String::from("4611911198408756429"); + let results = parse_float(value); + assert_eq!(results, 2.1); + } + + #[test] + fn test_parse_int() { + let value = String::from("2"); + let results = parse_int(value); + assert_eq!(results, 2); + } +} diff --git a/src/parser.rs b/src/parser.rs new file mode 100755 index 0000000..81e5780 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,508 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::{error, info}; + +use crate::dsc::SharedCacheStrings; +use crate::error::ParserError; +use crate::timesync::TimesyncBoot; +use crate::unified_log::{LogData, UnifiedLogData}; +use crate::uuidtext::UUIDText; +use std::fs; + +/// Parse the UUID files on a live system +pub fn collect_strings_system() -> Result, ParserError> { + let uuidtext_path = String::from("/private/var/db/uuidtext"); + collect_strings(&uuidtext_path) +} + +/// Parse the dsc (shared cache strings) files on a live system +pub fn collect_shared_strings_system() -> Result, ParserError> { + let dsc_path = String::from("/private/var/db/uuidtext/dsc"); + collect_shared_strings(&dsc_path) +} + +/// Parse the timesync files on a live system +pub fn collect_timesync_system() -> Result, ParserError> { + let timesync = String::from("/private/var/db/diagnostics/timesync"); + collect_timesync(×ync) +} + +/// Parse a tracev3 file and return the deconstructed log data +pub fn parse_log(full_path: &str) -> Result { + let buffer_results = fs::read(full_path); + + let buffer = match buffer_results { + Ok(results) => results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to read the tracev3 file {}: {:?}", + full_path, err + ); + return Err(ParserError::Read); + } + }; + info!("Read {} bytes for file {}", buffer.len(), full_path); + + let log_data_results = LogData::parse_unified_log(&buffer); + match log_data_results { + Ok((_, log_data)) => Ok(log_data), + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to parse the tracev3 file: {:?}", + err + ); + Err(ParserError::Tracev3Parse) + } + } +} + +/// Reconstruct Unified Log entries using the strings data, cached strings data, timesync data, and unified log. Provide bool to ignore log entries that are not able to be recontructed (additional tracev3 files needed) +/// Return a reconstructed log entries and any leftover Unified Log entries that could not be reconstructed (data may be stored in other tracev3 files) +// Log entries with Oversize string entries may have the data in a different tracev3 file. +pub fn build_log( + unified_data: &UnifiedLogData, + strings_data: &[UUIDText], + shared_strings: &[SharedCacheStrings], + timesync_data: &[TimesyncBoot], + exclude_missing: bool, +) -> (Vec, UnifiedLogData) { + LogData::build_log( + unified_data, + strings_data, + shared_strings, + timesync_data, + exclude_missing, + ) +} + +/// Parse all UUID files in provided directory. The directory should follow the same layout as the live system (ex: path/to/files//) +pub fn collect_strings(path: &str) -> Result, ParserError> { + let paths_results = fs::read_dir(path); + + let paths = match paths_results { + Ok(path) => path, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to read directory path: {:?}", + err + ); + return Err(ParserError::Dir); + } + }; + + let mut uuidtext_vec: Vec = Vec::new(); + // Start process to read a directory containing subdirectories that contain the uuidtext files + for path in paths { + let dir_entry = match path { + Ok(entry) => entry, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to get directory entry: {:?}", + err + ); + continue; + } + }; + + let type_results = dir_entry.file_type(); + let entry_type = match type_results { + Ok(dir_type) => dir_type, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to get directory entry type: {:?}", + err + ); + continue; + } + }; + + if entry_type.is_file() { + continue; + } + + let directory_results = dir_entry.file_name().into_string(); + let directory = match directory_results { + Ok(directory_path) => directory_path, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to convert path {:?} to string", + err + ); + continue; + } + }; + + // Currently expect the subdirectories to be structured like a live system (or .logarchive) + // they should be /private/var/db/uuidtext/<2 char values>/ (/private/var/db/uuidtext/1F/470CAE74D83AA1A6637FD0C5B1D365) + let first_two_uuid_chars = 2; + if directory.len() != first_two_uuid_chars { + continue; + } + + let dir_path = dir_entry.path(); + let uuidtext_path_results = fs::read_dir(dir_path); + let uuidtext_path = match uuidtext_path_results { + Ok(uuid_path) => uuid_path, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to read directory path for UUID files: {:?}", + err + ); + continue; + } + }; + + // Read all uuidtext files in directory + for uuid_data in uuidtext_path { + let uuidtext_full_path = match uuid_data { + Ok(uuid_entry) => uuid_entry, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to get directory uuid entry: {:?}", + err + ); + continue; + } + }; + + let full_path = uuidtext_full_path.path(); + let buffer_results = fs::read(&full_path); + let buffer = match buffer_results { + Ok(results) => results, + Err(err) => { + error!("[macos-unifiedlogs] Failed to read UUID file: {:?}", err); + continue; + } + }; + info!( + "Read {} bytes for file {}", + buffer.len(), + full_path.display().to_string() + ); + + let uuid_results = UUIDText::parse_uuidtext(&buffer); + let mut uuidtext_data = match uuid_results { + Ok((_, results)) => results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to parse UUID file {}: {:?}", + full_path.display().to_string(), + err + ); + continue; + } + }; + + // Track the uuidtext filename, this will be referenced by log entries via the Catalog (or log entry) + let uuid_file_name = uuidtext_full_path.file_name().into_string(); + match uuid_file_name { + // Only the last 14 characters of the UUID name are saved here. Limited chance of UUID collisions on a real system + Ok(uuid_file_string) => uuidtext_data.uuid = uuid_file_string, + Err(err) => { + error!("[macos-unifiedlogs] Failed to convert UUID filename {:?} to string. Unable to do base format string lookups", err); + continue; + } + } + + uuidtext_vec.push(uuidtext_data) + } + } + Ok(uuidtext_vec) +} + +/// Parse all dsc uuid files in provided directory +pub fn collect_shared_strings(path: &str) -> Result, ParserError> { + let paths_results = fs::read_dir(path); + + let paths = match paths_results { + Ok(results) => results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to read dsc directory {}: {:?}", + path, err + ); + return Err(ParserError::Path); + } + }; + + let mut shared_strings_vec: Vec = Vec::new(); + // Start process to read and parse uuid files related to dsc + for path in paths { + let data = match path { + Ok(path_results) => path_results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to get dsc directory entry: {:?}", + err + ); + continue; + } + }; + + let full_path = data.path(); + let buffer_results = fs::read(&full_path); + let buffer = match buffer_results { + Ok(results) => results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to read dsc file {}: {:?}", + full_path.display().to_string(), + err + ); + continue; + } + }; + + let shared_strings_data_results = SharedCacheStrings::parse_dsc(&buffer); + let mut shared_strings_data = match shared_strings_data_results { + Ok((_, results)) => results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to parse dsc file {}: {:?}", + full_path.display().to_string(), + err + ); + continue; + } + }; + + // Track the uuid filename, this will be referenced by log entries via the Catalog (or log entry) + let dsc_filename = data.file_name().into_string(); + match dsc_filename { + Ok(dsc_file_string) => shared_strings_data.dsc_uuid = dsc_file_string, + Err(err) => { + error!("[macos-unifiedlogs] Failed to convert dsc filename {:?} to string. Unable to do base format string lookups", err); + continue; + } + } + shared_strings_vec.push(shared_strings_data); + } + Ok(shared_strings_vec) +} + +/// Parse all timesync files in provided directory +pub fn collect_timesync(path: &str) -> Result, ParserError> { + let paths_results = fs::read_dir(path); + + let paths = match paths_results { + Ok(results) => results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to read timesync directory {}: {:?}", + path, err + ); + return Err(ParserError::Path); + } + }; + + let mut timesync_data_vec: Vec = Vec::new(); + // Start process to read and parse all timesync files + for path in paths { + let data = match path { + Ok(path_results) => path_results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to get timesync directory entry: {:?}", + err + ); + continue; + } + }; + + let full_path = data.path(); + let buffer_results = fs::read(&full_path); + let buffer = match buffer_results { + Ok(results) => results, + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to read timesync file {}: {:?}", + full_path.display().to_string(), + err + ); + continue; + } + }; + info!( + "Read {} bytes from timesync file {}", + buffer.len(), + full_path.display().to_string() + ); + + let timesync_results = TimesyncBoot::parse_timesync_data(&buffer); + match timesync_results { + Ok((_, mut timesync)) => timesync_data_vec.append(&mut timesync), + Err(err) => { + error!( + "[macos-unifiedlogs] Failed to parse timesync file {}: {:?}", + full_path.display().to_string(), + err + ); + continue; + } + } + } + Ok(timesync_data_vec) +} + +#[cfg(test)] +mod tests { + use crate::parser::{ + build_log, collect_shared_strings, collect_shared_strings_system, collect_strings, + collect_strings_system, collect_timesync, collect_timesync_system, parse_log, + }; + + use std::path::PathBuf; + + #[test] + fn test_collect_strings_system() { + let uuidtext_results = collect_strings_system().unwrap(); + assert!(uuidtext_results.len() > 100); + } + + #[test] + fn test_collect_timesync_system() { + let timesync_results = collect_timesync_system().unwrap(); + assert!(timesync_results.len() > 1); + } + + #[test] + fn test_collect_timesync_archive() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive/timesync"); + + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + assert_eq!(timesync_data.len(), 5); + assert_eq!(timesync_data[0].signature, 48048); + assert_eq!(timesync_data[0].unknown, 0); + assert_eq!( + timesync_data[0].boot_uuid, + "9A6A3124274A44B29ABF2BC9E4599B3B" + ); + assert_eq!(timesync_data[0].timesync.len(), 5); + assert_eq!(timesync_data[0].daylight_savings, 0); + assert_eq!(timesync_data[0].boot_time, 1642302206000000000); + assert_eq!(timesync_data[0].header_size, 48); + assert_eq!(timesync_data[0].timebase_denominator, 1); + assert_eq!(timesync_data[0].timebase_numerator, 1); + assert_eq!(timesync_data[0].timezone_offset_mins, 0); + } + + #[test] + fn test_collect_shared_strings_system() { + let shared_strings_results = collect_shared_strings_system().unwrap(); + assert!(shared_strings_results[0].ranges.len() > 1000); + assert!(shared_strings_results[0].uuids.len() > 1000); + assert!(shared_strings_results[0].number_ranges > 1000); + assert!(shared_strings_results[0].number_uuids > 1000); + } + + #[test] + fn test_shared_strings_archive() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive/dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + assert_eq!(shared_strings_results.len(), 2); + assert_eq!(shared_strings_results[0].number_uuids, 1976); + assert_eq!(shared_strings_results[0].number_ranges, 2993); + assert_eq!( + shared_strings_results[0].dsc_uuid, + "80896B329EB13A10A7C5449B15305DE2" + ); + assert_eq!(shared_strings_results[0].minor_version, 0); + assert_eq!(shared_strings_results[0].major_version, 1); + assert_eq!(shared_strings_results[0].ranges.len(), 2993); + assert_eq!(shared_strings_results[0].uuids.len(), 1976); + } + + #[test] + fn test_collect_strings_archive() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + + let strings_results = collect_strings(&test_path.display().to_string()).unwrap(); + assert_eq!(strings_results.len(), 536); + assert_eq!(strings_results[0].signature, 1719109785); + assert_eq!(strings_results[0].uuid, "5283D7FC2531558F2C1ACE9AF26A0F"); + assert_eq!(strings_results[0].entry_descriptors.len(), 2); + assert_eq!(strings_results[0].footer_data.len(), 48096); + assert_eq!(strings_results[0].number_entries, 2); + assert_eq!(strings_results[0].unknown_minor_version, 1); + assert_eq!(strings_results[0].unknown_major_version, 2); + } + + #[test] + fn test_parse_log() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + assert_eq!(log_data.catalog_data[0].firehose.len(), 99); + assert_eq!(log_data.catalog_data[0].simpledump.len(), 0); + assert_eq!(log_data.header.len(), 1); + assert_eq!( + log_data.catalog_data[0] + .catalog + .catalog_process_info_entries + .len(), + 46 + ); + assert_eq!(log_data.catalog_data[0].statedump.len(), 0); + } + + #[test] + fn test_build_log() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000002.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 207366); + assert_eq!(results[10].process, "/usr/libexec/lightsoutmanagementd"); + assert_eq!(results[10].subsystem, "com.apple.lom"); + assert_eq!(results[10].time, 1642302327364384800.0); + assert_eq!(results[10].activity_id, 0); + assert_eq!( + results[10].library, + "/System/Library/PrivateFrameworks/AppleLOM.framework/Versions/A/AppleLOM" + ); + assert_eq!(results[10].message, " LOM isSupported : No"); + assert_eq!(results[10].pid, 45); + assert_eq!(results[10].thread_id, 588); + assert_eq!(results[10].category, "device"); + assert_eq!(results[10].log_type, "Default"); + assert_eq!(results[10].event_type, "Log"); + assert_eq!(results[10].euid, 0); + assert_eq!(results[10].boot_uuid, "80D194AF56A34C54867449D2130D41BB"); + assert_eq!(results[10].timezone_name, "Pacific"); + assert_eq!(results[10].library_uuid, "D8E5AF1CAF4F3CEB8731E6F240E8EA7D"); + assert_eq!(results[10].process_uuid, "6C3ADF991F033C1C96C4ADFAA12D8CED"); + assert_eq!(results[10].raw_message, "%@ LOM isSupported : %s"); + } +} diff --git a/src/preamble.rs b/src/preamble.rs new file mode 100644 index 0000000..ea8e0da --- /dev/null +++ b/src/preamble.rs @@ -0,0 +1,68 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use std::mem::size_of; + +use nom::{ + bytes::complete::take, + number::complete::{le_u32, le_u64}, +}; + +#[derive(Debug)] +pub struct LogPreamble { + pub chunk_tag: u32, + pub chunk_sub_tag: u32, + pub chunk_data_size: u64, +} +impl LogPreamble { + /// Get the preamble (first 16 bytes of all Unified Log entries (chunks)) to detect the log (chunk) type. Ex: Firehose, Statedump, Simpledump, Catalog, etc + pub fn detect_preamble(data: &[u8]) -> nom::IResult<&[u8], LogPreamble> { + let mut preamble = LogPreamble { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + }; + + let (input, tag) = take(size_of::())(data)?; + let (input, sub_tag) = take(size_of::())(input)?; + let (input, data_size) = take(size_of::())(input)?; + + let (_, trace_tag) = le_u32(tag)?; + let (_, trace_sub_tag) = le_u32(sub_tag)?; + let (_, trace_data_size) = le_u64(data_size)?; + + preamble.chunk_tag = trace_tag; + preamble.chunk_sub_tag = trace_sub_tag; + preamble.chunk_data_size = trace_data_size; + Ok((input, preamble)) + } +} + +#[cfg(test)] +mod tests { + use super::LogPreamble; + + #[test] + fn test_detect_preamble() { + let test_preamble_header = [ + 0, 16, 0, 0, 17, 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + ]; + + let (_, preamble_data) = LogPreamble::detect_preamble(&test_preamble_header).unwrap(); + + assert_eq!(preamble_data.chunk_tag, 0x1000); + assert_eq!(preamble_data.chunk_sub_tag, 0x11); + assert_eq!(preamble_data.chunk_data_size, 0xd0); + + let test_catalog_chunk = [11, 96, 0, 0, 17, 0, 0, 0, 176, 31, 0, 0, 0, 0, 0, 0]; + let (_, preamble_data) = LogPreamble::detect_preamble(&test_catalog_chunk).unwrap(); + + assert_eq!(preamble_data.chunk_tag, 0x600b); + assert_eq!(preamble_data.chunk_sub_tag, 0x11); + assert_eq!(preamble_data.chunk_data_size, 0x1fb0); + } +} diff --git a/src/timesync.rs b/src/timesync.rs new file mode 100755 index 0000000..dfafb95 --- /dev/null +++ b/src/timesync.rs @@ -0,0 +1,416 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::error; +use nom::bytes::complete::take; +use nom::number::complete::{be_u128, le_i64, le_u16, le_u32, le_u64}; +use nom::Needed; +use std::mem::size_of; + +#[derive(Debug)] +pub struct TimesyncBoot { + pub signature: u16, + pub header_size: u16, + pub unknown: u32, + pub boot_uuid: String, + pub timebase_numerator: u32, + pub timebase_denominator: u32, + pub boot_time: i64, // Number of nanoseconds since UNIXEPOCH + pub timezone_offset_mins: u32, + pub daylight_savings: u32, // 0 is no DST, 1 is DST + pub timesync: Vec, +} + +#[derive(Debug)] +pub struct Timesync { + // Timestamps are in UTC + pub signature: u32, + pub unknown_flags: u32, + pub kernel_time: u64, // Mach continuous timestamp + pub walltime: i64, // Number of nanoseconds since UNIXEPOCH + pub timezone: u32, + pub daylight_savings: u32, // 0 is no DST, 1 is DST +} + +impl TimesyncBoot { + /// Parse the Unified Log timesync files + pub fn parse_timesync_data(data: &[u8]) -> nom::IResult<&[u8], Vec> { + let mut timesync_data: Vec = Vec::new(); + let mut input = data; + + let mut timesync_boot = TimesyncBoot { + signature: 0, + header_size: 0, + unknown: 0, + boot_uuid: String::new(), + timebase_numerator: 0, + timebase_denominator: 0, + boot_time: 0, + timezone_offset_mins: 0, + daylight_savings: 0, + timesync: Vec::new(), + }; + + while !input.is_empty() { + let (_, signature) = take(size_of::())(input)?; + let (_, timesync_signature) = le_u32(signature)?; + + let timesync_sig: u32 = 0x207354; + if timesync_signature == timesync_sig { + let (timesync_input, timesync) = TimesyncBoot::parse_timesync(input)?; + timesync_boot.timesync.push(timesync); + input = timesync_input; + } else { + if timesync_boot.signature != 0 { + timesync_data.push(timesync_boot); + } + let (timesync_input, timesync_boot_data) = + TimesyncBoot::parse_timesync_boot(input)?; + timesync_boot = timesync_boot_data; + input = timesync_input; + } + } + timesync_data.push(timesync_boot); + + Ok((input, timesync_data)) + } + + fn parse_timesync_boot(data: &[u8]) -> nom::IResult<&[u8], TimesyncBoot> { + let (input, signature) = take(size_of::())(data)?; + let (_, timesync_signature) = le_u16(signature)?; + + let expected_boot_signature = 0xbbb0; + if expected_boot_signature != timesync_signature { + error!( + "[macos-unifiedlogs] Incorrect Timesync boot header signature. Expected {}. Got: {}", + expected_boot_signature, timesync_signature + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + + let (input, header_size) = take(size_of::())(input)?; + let (input, unknown) = take(size_of::())(input)?; + let (input, boot_uuid) = take(size_of::())(input)?; + let (input, timebase_numerator) = take(size_of::())(input)?; + let (input, timebase_denominator) = take(size_of::())(input)?; + let (input, boot_time) = take(size_of::())(input)?; + let (input, timezone_offset_mins) = take(size_of::())(input)?; + let (input, daylight_savings) = take(size_of::())(input)?; + + let (_, timesync_header_size) = le_u16(header_size)?; + let (_, timesync_unknown) = le_u32(unknown)?; + let (_, timesync_boot_uuid) = be_u128(boot_uuid)?; + let (_, timesync_timebase_numerator) = le_u32(timebase_numerator)?; + let (_, timesync_timebase_denominator) = le_u32(timebase_denominator)?; + let (_, timesync_boot_time) = le_i64(boot_time)?; + let (_, timesync_timezone_offset_mins) = le_u32(timezone_offset_mins)?; + let (_, timesync_daylight_savings) = le_u32(daylight_savings)?; + + let timesync_boot = TimesyncBoot { + signature: timesync_signature, + header_size: timesync_header_size, + unknown: timesync_unknown, + boot_uuid: format!("{:X}", timesync_boot_uuid), + timebase_numerator: timesync_timebase_numerator, + timebase_denominator: timesync_timebase_denominator, + boot_time: timesync_boot_time, + timezone_offset_mins: timesync_timezone_offset_mins, + daylight_savings: timesync_daylight_savings, + timesync: Vec::new(), + }; + Ok((input, timesync_boot)) + } + + fn parse_timesync(data: &[u8]) -> nom::IResult<&[u8], Timesync> { + let mut timesync = Timesync { + signature: 0, + unknown_flags: 0, + kernel_time: 0, + walltime: 0, + timezone: 0, + daylight_savings: 0, + }; + let (input, signature) = take(size_of::())(data)?; + let (_, timesync_signature) = le_u32(signature)?; + + let expected_record_signature = 0x207354; + if expected_record_signature != timesync_signature { + error!( + "[macos-unifiedlogs] Incorrect Timesync record header signature. Expected {}. Got: {}", + expected_record_signature, timesync_signature + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + + let (input, unknown_flags) = take(size_of::())(input)?; + let (input, kernel_time) = take(size_of::())(input)?; + let (input, walltime) = take(size_of::())(input)?; + let (input, timezone) = take(size_of::())(input)?; + let (input, daylight_savings) = take(size_of::())(input)?; + + let (_, timesync_unknown_flags) = le_u32(unknown_flags)?; + let (_, timesync_kernel_time) = le_u64(kernel_time)?; + let (_, timesync_walltime) = le_i64(walltime)?; + let (_, timesync_timezone) = le_u32(timezone)?; + let (_, timesync_daylight_savings) = le_u32(daylight_savings)?; + + timesync.signature = timesync_signature; + timesync.unknown_flags = timesync_unknown_flags; + timesync.kernel_time = timesync_kernel_time; + timesync.walltime = timesync_walltime; + timesync.timezone = timesync_timezone; + timesync.daylight_savings = timesync_daylight_savings; + + Ok((input, timesync)) + } + + /// Calculate timestamp for firehose log entry + pub fn get_timestamp( + timesync_data: &[TimesyncBoot], + boot_uuid: &str, + firehose_log_delta_time: u64, + firehose_preamble_time: u64, + ) -> f64 { + /* Timestamp calculation logic: + Firehose Log entry timestamp is calculated by using firehose_preamble_time, firehose.continous_time_delta, and timesync timestamps + Firehose log header/preample contains a base timestamp + Ex: Firehose header base time is 2022-01-01 00:00:00 + All log entries following the header are continous from that base. EXCEPT when the base time is zero. If the base time is zero the TimeSync boot record boot time is used (boot time) + Ex: Firehose log entry time is +60 seconds + Timestamp would be 2022-01-01 00:01:00 + + (firehose_log_entry_continous_time = firehose.continous_time_delta | ((firehose.continous_time_delta_upper) << 32)) + firehose_log_delta_time = firehose_preamble_time + firehose_log_entry_continous_time + + Get all timesync boot records if timesync uuid equals boot uuid in tracev3 header data + + Loop through all timesync records from matching boot uuid until timesync cont_time/kernel time is greater than firehose_preamble_time + If firehose_header_time equals zero. Then the Timesync header walltime is used (the Timesync header cont_time/kernel time is then always zero) + Subtract timesync_cont_time/kernel time from firehose_log_delta_time + IF APPLE SILICON (ARM) is the architecture, then we need to mupltiple timesync_cont_time and firehose_log_delta_time by the timebase 125.0/3.0 to get the nanocsecond representation + + Add results to timesync_walltime (unix epoch in nanoseconds) + Final results is unix epoch timestamp in nano seconds + */ + + let mut timesync_continous_time = 0; + let mut timesync_walltime = 0; + + let mut larger_time = false; + + // Apple Intel uses 1/1 as the timebase + let mut timebase_adjustment = 1.0; + for timesync in timesync_data { + if boot_uuid != timesync.boot_uuid { + continue; + } + + if timesync.timebase_numerator == 125 && timesync.timebase_denominator == 3 { + // For Apple Silicon (ARM) we need to adjust the mach time by multiplying by 125.0/3.0 to get the accurate nanosecond count + timebase_adjustment = 125.0 / 3.0; + } + + // A preamble time of 0 means we need to use the timesync header boot time as our minimum value. + // We also set the timesync_continous_time to zero + if firehose_preamble_time == 0 { + timesync_continous_time = 0; + timesync_walltime = timesync.boot_time; + } + for timesync_record in ×ync.timesync { + if timesync_record.kernel_time > firehose_log_delta_time { + if timesync_continous_time == 0 && timesync_walltime == 0 { + timesync_continous_time = timesync_record.kernel_time; + timesync_walltime = timesync_record.walltime; + } + larger_time = true; + break; + } + + timesync_continous_time = timesync_record.kernel_time; + timesync_walltime = timesync_record.walltime; + } + // We should only break once we encountered a timesync_record.kernel_time greater than the firehose_log_delta_time + if larger_time { + break; + } + } + + let continous_time = (firehose_log_delta_time as f64 * timebase_adjustment) + - (timesync_continous_time as f64 * timebase_adjustment); + continous_time + timesync_walltime as f64 + } +} + +#[cfg(test)] +mod tests { + use crate::parser::collect_timesync; + use crate::timesync::TimesyncBoot; + use std::fs::File; + use std::io::Read; + use std::path::PathBuf; + + #[test] + fn test_parse_timesync_data() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push( + "tests/test_data/system_logs_big_sur.logarchive/timesync/0000000000000002.timesync", + ); + + let mut open = File::open(test_path).unwrap(); + let mut buffer = Vec::new(); + open.read_to_end(&mut buffer).unwrap(); + + let (_, timesync_data) = TimesyncBoot::parse_timesync_data(&buffer).unwrap(); + assert_eq!(timesync_data.len(), 5); + assert_eq!(timesync_data[0].timesync.len(), 5); + } + + #[test] + #[should_panic(expected = "Incomplete(Unknown)")] + fn test_timesync_bad_boot_header() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path + .push("tests/test_data/Bad Data/Timesync/Bad_Boot_header_0000000000000002.timesync"); + + let mut open = File::open(test_path).unwrap(); + let mut buffer = Vec::new(); + open.read_to_end(&mut buffer).unwrap(); + + let (_, _) = TimesyncBoot::parse_timesync_data(&buffer).unwrap(); + } + + #[test] + #[should_panic(expected = "Incomplete(Unknown)")] + fn test_timesync_bad_record_header() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path + .push("tests/test_data/Bad Data/Timesync/Bad_Record_header_0000000000000002.timesync"); + + let mut open = File::open(test_path).unwrap(); + let mut buffer = Vec::new(); + open.read_to_end(&mut buffer).unwrap(); + + let (_, _) = TimesyncBoot::parse_timesync_data(&buffer).unwrap(); + } + + #[test] + #[should_panic(expected = "Incomplete(Unknown)")] + fn test_timesync_bad_content() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Bad Data/Timesync/Bad_content_0000000000000002.timesync"); + + let mut open = File::open(test_path).unwrap(); + let mut buffer = Vec::new(); + open.read_to_end(&mut buffer).unwrap(); + + let (_, _) = TimesyncBoot::parse_timesync_data(&buffer).unwrap(); + } + + #[test] + #[should_panic(expected = "Incomplete(Unknown)")] + fn test_timesync_bad_file() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Bad Data/Timesync/BadFile.timesync"); + + let mut open = File::open(test_path).unwrap(); + let mut buffer = Vec::new(); + open.read_to_end(&mut buffer).unwrap(); + + let (_, _) = TimesyncBoot::parse_timesync_data(&buffer).unwrap(); + } + + #[test] + fn test_timesync() { + let test_data = [ + 84, 115, 32, 0, 0, 0, 0, 0, 165, 196, 104, 252, 1, 0, 0, 0, 216, 189, 100, 108, 116, + 158, 131, 22, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + let (_, timesync) = TimesyncBoot::parse_timesync(&test_data).unwrap(); + assert_eq!(timesync.signature, 0x207354); + assert_eq!(timesync.unknown_flags, 0); + assert_eq!(timesync.kernel_time, 8529691813); + assert_eq!(timesync.walltime, 1622314513655447000); + assert_eq!(timesync.timezone, 0); + assert_eq!(timesync.daylight_savings, 0); + } + + #[test] + fn test_timesync_boot() { + let test_data = [ + 176, 187, 48, 0, 0, 0, 0, 0, 132, 91, 13, 213, 1, 96, 69, 62, 172, 224, 56, 118, 12, + 123, 92, 29, 1, 0, 0, 0, 1, 0, 0, 0, 168, 167, 19, 176, 114, 158, 131, 22, 0, 0, 0, 0, + 0, 0, 0, 0, + ]; + let (_, timesync_boot) = TimesyncBoot::parse_timesync_boot(&test_data).unwrap(); + assert_eq!(timesync_boot.signature, 0xbbb0); + assert_eq!(timesync_boot.header_size, 48); + assert_eq!(timesync_boot.unknown, 0); + assert_eq!(timesync_boot.boot_uuid, "845B0DD50160453EACE038760C7B5C1D"); + assert_eq!(timesync_boot.timebase_numerator, 1); + assert_eq!(timesync_boot.timebase_denominator, 1); + assert_eq!(timesync_boot.boot_time, 1622314506201049000); + assert_eq!(timesync_boot.timezone_offset_mins, 0); + assert_eq!(timesync_boot.daylight_savings, 0); + } + + #[test] + fn test_get_timestamp() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive/timesync"); + + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + + let boot_uuid = "A2A9017676CF421C84DC9BBD6263FEE7"; + let firehose_preamble_continous_time = 2818326118; + + let results = TimesyncBoot::get_timestamp( + ×ync_data, + boot_uuid, + firehose_preamble_continous_time, + 1, + ); + assert_eq!(results, 1642304803060378889.0); + } + + #[test] + fn test_get_arm_timestamp() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_monterey.logarchive/timesync"); + + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + + let boot_uuid = "3E12B435814B4C62918CEBC0826F06B8"; + let firehose_preamble_continous_time = 2818326118; + + let results = TimesyncBoot::get_timestamp( + ×ync_data, + boot_uuid, + firehose_preamble_continous_time, + 1, + ); + assert_eq!(results, 1650767519086487000.0); + } + + #[test] + fn test_get_arm_timestamp_use_boot_time() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_monterey.logarchive/timesync"); + + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + + let boot_uuid = "3E12B435814B4C62918CEBC0826F06B8"; + let firehose_preamble_continous_time = 9898326118; + + let results = TimesyncBoot::get_timestamp( + ×ync_data, + boot_uuid, + firehose_preamble_continous_time, + 0, + ); + assert_eq!(results, 1650767813342574583.0); + } +} diff --git a/src/unified_log.rs b/src/unified_log.rs new file mode 100755 index 0000000..45b62ee --- /dev/null +++ b/src/unified_log.rs @@ -0,0 +1,1314 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +//! Parse macOS Unified Log data +//! +//! Provides a simple library to parse the macOS Unified Log format. + +use crate::catalog::CatalogChunk; +use crate::chunks::firehose::activity::FirehoseActivity; +use crate::chunks::firehose::firehose_log::{Firehose, FirehoseItemInfo, FirehosePreamble}; +use crate::chunks::firehose::nonactivity::FirehoseNonActivity; +use crate::chunks::firehose::signpost::FirehoseSignpost; +use crate::chunks::firehose::trace::FirehoseTrace; +use crate::chunks::oversize::Oversize; +use crate::chunks::simpledump::SimpleDump; +use crate::chunks::statedump::Statedump; +use crate::chunkset::ChunksetChunk; +use crate::dsc::SharedCacheStrings; +use crate::header::HeaderChunk; +use crate::message::format_firehose_log_message; +use crate::preamble::LogPreamble; +use crate::timesync::TimesyncBoot; +use log::{error, warn}; +use nom::bytes::complete::take; +use regex::Regex; +use serde::Serialize; + +use crate::util::{extract_string, padding_size}; +use crate::uuidtext::UUIDText; + +#[derive(Debug, Clone)] +pub struct UnifiedLogData { + pub header: Vec, + pub catalog_data: Vec, + pub oversize: Vec, // Keep a global cache of oversize string +} + +#[derive(Debug, Clone)] +pub struct UnifiedLogCatalogData { + pub catalog: CatalogChunk, + pub firehose: Vec, + pub simpledump: Vec, + pub statedump: Vec, + pub oversize: Vec, +} + +#[derive(Debug, Serialize)] +pub struct LogData { + pub subsystem: String, + pub thread_id: u64, + pub pid: u64, + pub euid: u32, + pub library: String, + pub library_uuid: String, + pub activity_id: u64, + pub time: f64, + pub category: String, + pub event_type: String, + pub log_type: String, + pub process: String, + pub process_uuid: String, + pub message: String, + pub raw_message: String, + pub boot_uuid: String, + pub timezone_name: String, + pub message_entries: Vec, +} + +impl LogData { + /// Parse the Unified log data read from a tracev3 file + pub fn parse_unified_log(data: &[u8]) -> nom::IResult<&[u8], UnifiedLogData> { + let mut unified_log_data_true = UnifiedLogData { + header: Vec::new(), + catalog_data: Vec::new(), + oversize: Vec::new(), + }; + + let mut catalog_data = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + let mut input = data; + let chunk_preamble_size = 16; // Include preamble size in total chunk size + + let header_chunk = 0x1000; + let catalog_chunk = 0x600b; + let chunkset_chunk = 0x600d; + // Loop through traceV3 file until all file contents are read + while !input.is_empty() { + let (_, preamble) = LogPreamble::detect_preamble(input)?; + let chunk_size = preamble.chunk_data_size; + + // Grab all data associated with Unified Log entry (chunk) + let (data, chunk_data) = take(chunk_size + chunk_preamble_size)(input)?; + + if preamble.chunk_tag == header_chunk { + LogData::get_header_data(chunk_data, &mut unified_log_data_true); + } else if preamble.chunk_tag == catalog_chunk { + if catalog_data.catalog.chunk_tag != 0 { + unified_log_data_true.catalog_data.push(catalog_data); + } + catalog_data = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + LogData::get_catalog_data(chunk_data, &mut catalog_data); + } else if preamble.chunk_tag == chunkset_chunk { + LogData::get_chunkset_data( + chunk_data, + &mut catalog_data, + &mut unified_log_data_true, + ); + } else { + error!( + "[macos-unifiedlogs] Unknown chunk type: {:?}", + preamble.chunk_tag + ); + } + + let padding_size = padding_size(preamble.chunk_data_size); + if data.len() < padding_size as usize { + break; + } + let (data, _) = take(padding_size)(data)?; + if data.is_empty() { + break; + } + input = data; + if input.len() < chunk_preamble_size as usize { + warn!( + "Not enough data for preamble header, needed 16 bytes. Got: {:?}", + input.len() + ); + break; + } + } + // Make sure to get the last catalog + if catalog_data.catalog.chunk_tag != 0 { + unified_log_data_true.catalog_data.push(catalog_data); + } + Ok((input, unified_log_data_true)) + } + + /// Reconstruct Unified Log entries using the binary strings data, cached strings data, timesync data, and unified log. Provide bool to ignore log entries that are not able to be recontructed (additional tracev3 files needed) + /// Return a reconstructed log entries and any leftover Unified Log entries that could not be reconstructed (data may be stored in other tracev3 files) + pub fn build_log( + unified_log_data: &UnifiedLogData, + strings_data: &[UUIDText], + shared_strings: &[SharedCacheStrings], + timesync_data: &[TimesyncBoot], + exclude_mssing: bool, + ) -> (Vec, UnifiedLogData) { + let mut log_data_vec: Vec = Vec::new(); + // Need to keep track of any log entries that fail to find Oversize strings (sometimes the strings may be in other log files that have not been parsed yet) + let mut missing_unified_log_data_vec = UnifiedLogData { + header: Vec::new(), + catalog_data: Vec::new(), + oversize: Vec::new(), + }; + /* + Crazy Regex to try to get all log message formatters + Formatters are based off of printf formatters with additional Apple values + ( # start of capture group 1 + % # literal "%" + (?: # first option + + (?:{[^}]+}?) # Get String formatters with %{} values. Ex: %{public}#llx with team ID %{public}@ + (?:[-+0#]{0,5}) # optional flags + (?:\d+|\*)? # width + (?:\.(?:\d+|\*))? # precision + (?:h|hh|l|ll|t|q|w|I|z|I32|I64)? # size + [cCdiouxXeEfgGaAnpsSZPm@}] # type + + | # OR get regular string formatters, ex: %s, %d + + (?:[-+0 #]{0,5}) # optional flags + (?:\d+|\*)? # width + (?:\.(?:\d+|\*))? # precision + (?:h|hh|l|ll|w|I|t|q|z|I32|I64)? # size + [cCdiouxXeEfgGaAnpsSZPm@%] # type + )) + */ + let message_re_result = Regex::new( + r"(%(?:(?:\{[^}]+}?)(?:[-+0#]{0,5})(?:\d+|\*)?(?:\.(?:\d+|\*))?(?:h|hh|l|ll|w|I|z|t|q|I32|I64)?[cmCdiouxXeEfgGaAnpsSZP@}]|(?:[-+0 #]{0,5})(?:\d+|\*)?(?:\.(?:\d+|\*))?(?:h|hh|l||q|t|ll|w|I|z|I32|I64)?[cmCdiouxXeEfgGaAnpsSZP@%]))", + ); + let message_re = match message_re_result { + Ok(result) => result, + Err(err) => { + error!( + "Failed to compile regex for printf format parsing: {:?}", + err + ); + return (log_data_vec, missing_unified_log_data_vec); + } + }; + + for catalog_data in &unified_log_data.catalog_data { + for (preamble_index, preamble) in catalog_data.firehose.iter().enumerate() { + for (firehose_index, firehose) in preamble.public_data.iter().enumerate() { + // The continous time is actually 6 bytes long. Combining 4 bytes and 2 bytes + let firehose_log_entry_continous_time = + u64::from(firehose.continous_time_delta) + | ((u64::from(firehose.continous_time_delta_upper)) << 32); + + let continous_time = + preamble.base_continous_time + firehose_log_entry_continous_time; + + // Calculate the timestamp for the log entry + let timestamp = TimesyncBoot::get_timestamp( + timesync_data, + &unified_log_data.header[0].boot_uuid, + continous_time, + preamble.base_continous_time, + ); + + // Our struct format to hold and show the log data + let mut log_data = LogData { + subsystem: String::new(), + thread_id: firehose.thread_id, + pid: CatalogChunk::get_pid( + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ), + library: String::new(), + activity_id: 0, + time: timestamp, + category: String::new(), + log_type: LogData::get_log_type( + &firehose.unknown_log_type, + &firehose.unknown_log_activity_type, + ), + process: String::new(), + message: String::new(), + event_type: LogData::get_event_type(&firehose.unknown_log_activity_type), + euid: CatalogChunk::get_euid( + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ), + boot_uuid: unified_log_data.header[0].boot_uuid.to_owned(), + timezone_name: unified_log_data.header[0] + .timezone_path + .split('/') + .last() + .unwrap_or("Unknown Timezone Name") + .to_string(), + library_uuid: String::new(), + process_uuid: String::new(), + raw_message: String::new(), + message_entries: Vec::new(), + }; + + // 0x4 - Non-activity log entry. Ex: log default, log error, etc + // 0x2 - Activity log entry. Ex: activity create + // 0x7 - Loss log entry. Ex: loss + // 0x6 - Signpost entry. Ex: process signpost, thread signpost, system signpost + // 0x3 - Trace log entry. Ex: trace default + match firehose.unknown_log_activity_type { + 0x4 => { + log_data.activity_id = + u64::from(firehose.firehose_non_activity.unknown_activity_id); + let message_data = + FirehoseNonActivity::get_firehose_nonactivity_strings( + &firehose.firehose_non_activity, + strings_data, + shared_strings, + u64::from(firehose.format_string_location), + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ); + + match message_data { + Ok((_, results)) => { + log_data.library = results.library; + log_data.library_uuid = results.library_uuid; + log_data.process = results.process; + log_data.process_uuid = results.process_uuid; + log_data.raw_message = results.format_string.to_owned(); + + // If the non-activity log entry has a data ref value then the message strings are stored in an oversize log entry + let log_message = + if firehose.firehose_non_activity.data_ref_value != 0 { + let oversize_strings = Oversize::get_oversize_strings( + u32::from( + firehose.firehose_non_activity.data_ref_value, + ), + preamble.first_number_proc_id, + preamble.second_number_proc_id, + &unified_log_data.oversize, + ); + // Format and map the log strings with the message format string found UUIDText or shared string file + format_firehose_log_message( + results.format_string, + &oversize_strings, + &message_re, + ) + } else { + // Format and map the log strings with the message format string found UUIDText or shared string file + format_firehose_log_message( + results.format_string, + &firehose.message.item_info, + &message_re, + ) + }; + // If we are tracking missing data (due to it being stored in another log file). Add missing data to vec to track and parse again once we got all data + if exclude_mssing + && log_message.contains("") + { + LogData::add_missing( + catalog_data, + preamble_index, + firehose_index, + &unified_log_data.header, + &mut missing_unified_log_data_vec, + preamble, + ); + continue; + } + + if !firehose.message.backtrace_strings.is_empty() { + log_data.message = format!( + "Backtrace:\n{:}\n{:}", + firehose.message.backtrace_strings.join("\n"), + log_message + ); + } else { + log_data.message = log_message; + } + + log_data.message_entries = firehose.message.item_info.to_owned() + } + Err(err) => { + warn!("[macos-unifiedlogs] Failed to get message string data for firehose non-activity log entry: {:?}", err); + } + } + + if firehose.firehose_non_activity.subsystem_value != 0 { + let results = CatalogChunk::get_subsystem( + &firehose.firehose_non_activity.subsystem_value, + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ); + match results { + Ok((_, subsystem)) => { + log_data.subsystem = subsystem.subsystem; + log_data.category = subsystem.category; + } + Err(err) => warn!( + "[macos-unifiedlogs] Failed to get subsystem: {:?}", + err + ), + } + } + } + 0x7 => { + // No message data in loss entries + log_data.log_type = String::new(); + } + 0x2 => { + log_data.activity_id = + u64::from(firehose.firehose_activity.unknown_activity_id); + let message_data = FirehoseActivity::get_firehose_activity_strings( + &firehose.firehose_activity, + strings_data, + shared_strings, + u64::from(firehose.format_string_location), + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ); + match message_data { + Ok((_, results)) => { + log_data.library = results.library; + log_data.library_uuid = results.library_uuid; + log_data.process = results.process; + log_data.process_uuid = results.process_uuid; + log_data.raw_message = results.format_string.to_owned(); + + let log_message = format_firehose_log_message( + results.format_string, + &firehose.message.item_info, + &message_re, + ); + + if exclude_mssing + && log_message.contains("") + { + LogData::add_missing( + catalog_data, + preamble_index, + firehose_index, + &unified_log_data.header, + &mut missing_unified_log_data_vec, + preamble, + ); + continue; + } + if !firehose.message.backtrace_strings.is_empty() { + log_data.message = format!( + "Backtrace:\n{:}\n{:}", + firehose.message.backtrace_strings.join("\n"), + log_message + ); + } else { + log_data.message = log_message; + } + } + Err(err) => { + warn!("[macos-unifiedlogs] Failed to get message string data for firehose activity log entry: {:?}", err); + } + } + } + 0x6 => { + log_data.activity_id = + u64::from(firehose.firehose_signpost.unknown_activity_id); + let message_data = FirehoseSignpost::get_firehose_signpost( + &firehose.firehose_signpost, + strings_data, + shared_strings, + u64::from(firehose.format_string_location), + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ); + match message_data { + Ok((_, results)) => { + log_data.library = results.library; + log_data.library_uuid = results.library_uuid; + log_data.process = results.process; + log_data.process_uuid = results.process_uuid; + log_data.raw_message = results.format_string.to_owned(); + + let mut log_message = + if firehose.firehose_non_activity.data_ref_value != 0 { + let oversize_strings = Oversize::get_oversize_strings( + u32::from( + firehose.firehose_non_activity.data_ref_value, + ), + preamble.first_number_proc_id, + preamble.second_number_proc_id, + &unified_log_data.oversize, + ); + // Format and map the log strings with the message format string found UUIDText or shared string file + format_firehose_log_message( + results.format_string, + &oversize_strings, + &message_re, + ) + } else { + // Format and map the log strings with the message format string found UUIDText or shared string file + format_firehose_log_message( + results.format_string, + &firehose.message.item_info, + &message_re, + ) + }; + if exclude_mssing + && log_message.contains("") + { + LogData::add_missing( + catalog_data, + preamble_index, + firehose_index, + &unified_log_data.header, + &mut missing_unified_log_data_vec, + preamble, + ); + continue; + } + + log_message = format!( + "Signpost ID: {:X} - Signpost Name: {:X}\n {}", + firehose.firehose_signpost.signpost_id, + firehose.firehose_signpost.signpost_name, + log_message + ); + + if !firehose.message.backtrace_strings.is_empty() { + log_data.message = format!( + "Backtrace:\n{:}\n{:}", + firehose.message.backtrace_strings.join("\n"), + log_message + ); + } else { + log_data.message = log_message; + } + } + Err(err) => { + warn!("[macos-unifiedlogs] Failed to get message string data for firehose signpost log entry: {:?}", err); + } + } + if firehose.firehose_signpost.subsystem != 0 { + let results = CatalogChunk::get_subsystem( + &firehose.firehose_signpost.subsystem, + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ); + match results { + Ok((_, subsystem)) => { + log_data.subsystem = subsystem.subsystem; + log_data.category = subsystem.category; + } + Err(err) => warn!( + "[macos-unifiedlogs] Failed to get subsystem: {:?}", + err + ), + } + } + } + 0x3 => { + let message_data = FirehoseTrace::get_firehose_trace_strings( + strings_data, + u64::from(firehose.format_string_location), + &preamble.first_number_proc_id, + &preamble.second_number_proc_id, + &catalog_data.catalog, + ); + match message_data { + Ok((_, results)) => { + log_data.library = results.library; + log_data.library_uuid = results.library_uuid; + log_data.process = results.process; + log_data.process_uuid = results.process_uuid; + + let log_message = format_firehose_log_message( + results.format_string, + &firehose.message.item_info, + &message_re, + ); + + if exclude_mssing + && log_message.contains("") + { + LogData::add_missing( + catalog_data, + preamble_index, + firehose_index, + &unified_log_data.header, + &mut missing_unified_log_data_vec, + preamble, + ); + continue; + } + if !firehose.message.backtrace_strings.is_empty() { + log_data.message = format!( + "Backtrace:\n{:}\n{:}", + firehose.message.backtrace_strings.join("\n"), + log_message + ); + } else { + log_data.message = log_message; + } + } + Err(err) => { + warn!("[macos-unifiedlogs] Failed to get message string data for firehose activity log entry: {:?}", err); + } + } + } + _ => error!( + "[macos-unifiedlogs] Parsed unknown log firehose data: {:?}", + firehose + ), + } + log_data_vec.push(log_data); + } + } + + for simpledump in &catalog_data.simpledump { + let no_firehose_preamble = 1; + let log_data = LogData { + subsystem: simpledump.subsystem.to_owned(), + thread_id: simpledump.thread_id, + pid: simpledump.first_proc_id, + library: String::new(), + activity_id: 0, + time: TimesyncBoot::get_timestamp( + timesync_data, + &unified_log_data.header[0].boot_uuid, + simpledump.continous_time, + no_firehose_preamble, + ), + category: String::new(), + log_type: String::new(), + process: String::new(), + message: simpledump.message_string.to_owned(), + event_type: String::from("Simpledump"), + euid: 0, + boot_uuid: unified_log_data.header[0].boot_uuid.to_owned(), + timezone_name: unified_log_data.header[0] + .timezone_path + .split('/') + .last() + .unwrap_or("Unknown Timezone Name") + .to_string(), + library_uuid: simpledump.sender_uuid.to_owned(), + process_uuid: simpledump.dsc_uuid.to_owned(), + raw_message: String::new(), + message_entries: Vec::new(), + }; + log_data_vec.push(log_data); + } + + for statedump in &catalog_data.statedump { + let plist_type = 1; + let protocol_buffer = 2; + let custom_object = 3; + let mut data_string = String::new(); + + let no_firehose_preamble = 1; + if statedump.unknown_data_type == plist_type { + data_string = Statedump::parse_statedump_plist(&statedump.statedump_data); + } else if statedump.unknown_data_type == custom_object { + data_string = String::from("Statedump Custom Object"); + } else if statedump.unknown_data_type == protocol_buffer { + data_string = String::from("Statedump Protocol Buffer"); + } else if !&statedump.statedump_data.is_empty() { + warn!( + "Unknown statedump data type: {}", + statedump.unknown_data_type + ); + let results = extract_string(&statedump.statedump_data); + match results { + Ok((_, string_data)) => data_string = string_data, + Err(err) => error!( + "[macos-unifiedlogs] Failed to extract string from statedump: {:?}", + err + ), + } + } + + let log_data = LogData { + subsystem: String::new(), + thread_id: 0, + pid: statedump.first_proc_id, + library: String::new(), + activity_id: statedump.activity_id, + time: TimesyncBoot::get_timestamp( + timesync_data, + &unified_log_data.header[0].boot_uuid, + statedump.continuous_time, + no_firehose_preamble, + ), + category: String::new(), + event_type: String::from("Statedump"), + process: String::new(), + message: format!( + "title: {:?}\nObject Type: {:?}\n Object Type: {:?}\n{:?}", + statedump.unknown_name, + statedump.unknown_object_type_string_1, + statedump.unknown_object_type_string_2, + data_string + ), + log_type: String::new(), + euid: 0, + boot_uuid: unified_log_data.header[0].boot_uuid.to_owned(), + timezone_name: unified_log_data.header[0] + .timezone_path + .split('/') + .last() + .unwrap_or("Unknown Timezone Name") + .to_string(), + library_uuid: String::new(), + process_uuid: String::new(), + raw_message: String::new(), + message_entries: Vec::new(), + }; + log_data_vec.push(log_data); + } + } + + (log_data_vec, missing_unified_log_data_vec) + } + + // Return log type based on parsed log data + fn get_log_type(log_type: &u8, activity_type: &u8) -> String { + match log_type { + 0x1 => { + let activity = 2; + if activity_type == &activity { + String::from("Create") + } else { + String::from("Info") + } + } + 0x2 => String::from("Debug"), + 0x3 => String::from("Useraction"), + 0x10 => String::from("Error"), + 0x11 => String::from("Fault"), + 0x80 => String::from("Process Signpost Event"), + 0x81 => String::from("Process Signpost Start"), + 0x82 => String::from("Process Signpost End"), + 0xc0 => String::from("System Signpost Event"), // Not seen but may exist? + 0xc1 => String::from("System Signpost Start"), + 0xc2 => String::from("System Signpost End"), + 0x40 => String::from("Thread Signpost Event"), // Not seen but may exist? + 0x41 => String::from("Thread Signpost Start"), + 0x42 => String::from("Thread Signpost End"), + _ => String::from("Default"), + } + } + + // Return the log event type based on parsed log data + fn get_event_type(event_type: &u8) -> String { + match event_type { + 0x4 => String::from("Log"), + 0x2 => String::from("Activity"), + 0x3 => String::from("Trace"), + 0x6 => String::from("Signpost"), + 0x7 => String::from("Loss"), + _ => String::from("Unknown"), + } + } + + // Get the header of the Unified Log data (tracev3 file) + fn get_header_data(data: &[u8], unified_log_data: &mut UnifiedLogData) { + let header_results = HeaderChunk::parse_header(data); + match header_results { + Ok((_, header_data)) => unified_log_data.header.push(header_data), + Err(err) => error!("[macos-unifiedlogs] Failed to parse header data: {:?}", err), + } + } + + // Get the Catalog of the Unified Log data (tracev3 file) + fn get_catalog_data(data: &[u8], unified_log_data: &mut UnifiedLogCatalogData) { + let catalog_results = CatalogChunk::parse_catalog(data); + match catalog_results { + Ok((_, catalog_data)) => unified_log_data.catalog = catalog_data, + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse catalog data: {:?}", + err + ), + } + } + + // Get the Chunkset of the Unified Log data (tracev3) + fn get_chunkset_data( + data: &[u8], + catalog_data: &mut UnifiedLogCatalogData, + unified_log_data: &mut UnifiedLogData, + ) { + // Parse and decompress the chunkset entries + let chunkset_data_results = ChunksetChunk::parse_chunkset(data); + match chunkset_data_results { + Ok((_, chunkset_data)) => { + // Parse the decompressed data which contains the log data + let _result = ChunksetChunk::parse_chunkset_data( + &chunkset_data.decompressed_data, + catalog_data, + ); + unified_log_data.oversize.append(&mut catalog_data.oversize); + } + Err(err) => error!( + "[macos-unifiedlogs] Failed to parse chunkset data: {:?}", + err + ), + } + } + + // Track log entries that are missing data that could in another tracev3 file + fn track_missing( + first_proc_id: u64, + second_proc_id: u32, + time: u64, + firehose: Firehose, + ) -> FirehosePreamble { + FirehosePreamble { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + first_number_proc_id: first_proc_id, + second_number_proc_id: second_proc_id, + collapsed: 0, + unknown: Vec::new(), + public_data_size: 0, + private_data_virtual_offset: 0, + unkonwn2: 0, + unknown3: 0, + base_continous_time: time, + public_data: vec![firehose], + ttl: 0, + } + } + + // Add all missing log entries to log data tracker. Log data may be in another file. Mainly related to logs with that have Oversize data + fn add_missing( + catalog_data: &UnifiedLogCatalogData, + preamble_index: usize, + firehose_index: usize, + header: &[HeaderChunk], + missing_unified_log_data_vec: &mut UnifiedLogData, + preamble: &FirehosePreamble, + ) { + let missing_firehose = LogData::track_missing( + catalog_data.firehose[preamble_index].first_number_proc_id, + catalog_data.firehose[preamble_index].second_number_proc_id, + catalog_data.firehose[preamble_index].base_continous_time, + preamble.public_data[firehose_index].to_owned(), + ); + let mut missing_unified_log_data = UnifiedLogCatalogData { + catalog: catalog_data.catalog.to_owned(), + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + missing_unified_log_data.firehose.push(missing_firehose); + missing_unified_log_data_vec.header = header.to_owned(); + + missing_unified_log_data_vec + .catalog_data + .push(missing_unified_log_data); + } +} + +#[cfg(test)] +mod tests { + use std::{fs, path::PathBuf}; + + use crate::{ + catalog::CatalogChunk, + chunks::firehose::activity::FirehoseActivity, + chunks::firehose::firehose_log::{Firehose, FirehoseItemData}, + chunks::firehose::flags::FirehoseFormatters, + chunks::firehose::loss::FirehoseLoss, + chunks::firehose::nonactivity::FirehoseNonActivity, + chunks::firehose::signpost::FirehoseSignpost, + chunks::firehose::trace::FirehoseTrace, + parser::{collect_shared_strings, collect_strings, collect_timesync, parse_log}, + unified_log::UnifiedLogCatalogData, + }; + + use super::{LogData, UnifiedLogData}; + + #[test] + fn test_parse_unified_log() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push( + "tests/test_data/system_logs_big_sur.logarchive/Persist/0000000000000002.tracev3", + ); + + let buffer = fs::read(test_path).unwrap(); + + let (_, results) = LogData::parse_unified_log(&buffer).unwrap(); + assert_eq!(results.catalog_data.len(), 56); + assert_eq!(results.header.len(), 1); + assert_eq!(results.oversize.len(), 12); + } + + #[test] + fn test_bad_log_header() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Bad Data/TraceV3/Bad_header_0000000000000005.tracev3"); + + let buffer = fs::read(test_path).unwrap(); + let (_, results) = LogData::parse_unified_log(&buffer).unwrap(); + assert_eq!(results.catalog_data.len(), 36); + assert_eq!(results.header.len(), 0); + assert_eq!(results.oversize.len(), 28); + } + + #[test] + #[should_panic(expected = "Eof")] + fn test_bad_log_content() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Bad Data/TraceV3/Bad_content_0000000000000005.tracev3"); + + let buffer = fs::read(test_path).unwrap(); + let (_, _) = LogData::parse_unified_log(&buffer).unwrap(); + } + + #[test] + #[should_panic(expected = "Eof")] + fn test_bad_log_file() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Bad Data/TraceV3/00.tracev3"); + + let buffer = fs::read(test_path).unwrap(); + let (_, _) = LogData::parse_unified_log(&buffer).unwrap(); + } + + #[test] + fn test_build_log() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = + collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000002.tracev3"); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = LogData::build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 207366); + assert_eq!(results[0].process, "/usr/libexec/lightsoutmanagementd"); + assert_eq!(results[0].subsystem, "com.apple.lom"); + assert_eq!(results[0].time, 1642302326434850732.0); + assert_eq!(results[0].activity_id, 0); + assert_eq!(results[0].library, "/usr/libexec/lightsoutmanagementd"); + assert_eq!(results[0].library_uuid, "6C3ADF991F033C1C96C4ADFAA12D8CED"); + assert_eq!(results[0].process_uuid, "6C3ADF991F033C1C96C4ADFAA12D8CED"); + assert_eq!(results[0].message, "LOMD Start"); + assert_eq!(results[0].pid, 45); + assert_eq!(results[0].thread_id, 588); + assert_eq!(results[0].category, "device"); + assert_eq!(results[0].log_type, "Default"); + assert_eq!(results[0].event_type, "Log"); + assert_eq!(results[0].euid, 0); + assert_eq!(results[0].boot_uuid, "80D194AF56A34C54867449D2130D41BB"); + assert_eq!(results[0].timezone_name, "Pacific"); + assert_eq!(results[0].raw_message, "LOMD Start"); + } + + #[test] + fn test_get_log_type() { + let mut log_type = 0x2; + let activity_type = 0x2; + + let mut log_string = LogData::get_log_type(&log_type, &activity_type); + assert_eq!(log_string, "Debug"); + log_type = 0x1; + log_string = LogData::get_log_type(&log_type, &activity_type); + assert_eq!(log_string, "Create"); + } + + #[test] + fn test_get_event_type() { + let event_type = 0x2; + let event_string = LogData::get_event_type(&event_type); + assert_eq!(event_string, "Activity"); + } + + #[test] + fn test_get_header_data() { + let test_chunk_header = [ + 0, 16, 0, 0, 17, 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 15, 105, + 217, 162, 204, 126, 0, 0, 48, 215, 18, 98, 0, 0, 0, 0, 203, 138, 9, 0, 44, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 97, 0, 0, 8, 0, 0, 0, 6, 112, 124, 198, 169, 153, 1, 0, 1, 97, + 0, 0, 56, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 50, 49, 65, 53, 53, 57, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 77, 97, 99, 66, 111, 111, 107, 80, 114, 111, 49, 54, 44, 49, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 97, 0, 0, 24, 0, 0, 0, 195, 32, 184, 206, 151, + 250, 77, 165, 159, 49, 125, 57, 46, 56, 156, 234, 85, 0, 0, 0, 0, 0, 0, 0, 3, 97, 0, 0, + 48, 0, 0, 0, 47, 118, 97, 114, 47, 100, 98, 47, 116, 105, 109, 101, 122, 111, 110, 101, + 47, 122, 111, 110, 101, 105, 110, 102, 111, 47, 65, 109, 101, 114, 105, 99, 97, 47, 78, + 101, 119, 95, 89, 111, 114, 107, 0, 0, 0, 0, 0, 0, + ]; + let mut data = UnifiedLogData { + header: Vec::new(), + catalog_data: Vec::new(), + oversize: Vec::new(), + }; + + LogData::get_header_data(&test_chunk_header, &mut data); + assert_eq!(data.header.len(), 1); + } + + #[test] + fn test_get_catalog_data() { + let test_chunk_catalog = [ + 11, 96, 0, 0, 17, 0, 0, 0, 208, 1, 0, 0, 0, 0, 0, 0, 32, 0, 96, 0, 1, 0, 160, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 20, 165, 44, 35, 253, 233, 2, 0, 43, 239, 210, 12, 24, 236, 56, 56, + 129, 79, 43, 78, 90, 243, 188, 236, 61, 5, 132, 95, 63, 101, 53, 143, 158, 191, 34, 54, + 231, 114, 172, 1, 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 83, 107, 121, 76, 105, + 103, 104, 116, 0, 112, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 95, 105, 110, + 115, 116, 114, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 0, 116, 114, 97, 99, + 105, 110, 103, 46, 115, 116, 97, 108, 108, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 158, + 0, 0, 0, 0, 0, 0, 0, 55, 1, 0, 0, 158, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 19, 0, 78, 0, 0, 0, 47, 0, 0, 0, 0, 0, + 246, 113, 118, 43, 250, 233, 2, 0, 62, 195, 90, 26, 9, 234, 2, 0, 120, 255, 0, 0, 0, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 48, 89, 60, 28, 9, 234, 2, 0, + 99, 50, 207, 40, 18, 234, 2, 0, 112, 240, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 19, 0, 47, 0, 153, 6, 208, 41, 18, 234, 2, 0, 0, 214, 108, 78, 32, 234, 2, 0, + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 128, 0, 87, + 79, 32, 234, 2, 0, 137, 5, 2, 205, 41, 234, 2, 0, 88, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 185, 11, 2, 205, 41, 234, 2, 0, 172, 57, 107, + 20, 56, 234, 2, 0, 152, 255, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, + 0, 47, 0, 53, 172, 105, 21, 56, 234, 2, 0, 170, 167, 194, 43, 68, 234, 2, 0, 144, 255, + 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, 220, 202, 171, 57, + 68, 234, 2, 0, 119, 171, 170, 119, 76, 234, 2, 0, 240, 254, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 19, 0, 47, 0, + ]; + let mut data = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + LogData::get_catalog_data(&test_chunk_catalog, &mut data); + assert_eq!(data.catalog.chunk_tag, 0x600b); + assert_eq!(data.catalog.chunk_sub_tag, 17); + assert_eq!(data.catalog.chunk_data_size, 464); + assert_eq!(data.catalog.catalog_subsystem_strings_offset, 32); + assert_eq!(data.catalog.catalog_process_info_entries_offset, 96); + assert_eq!(data.catalog.number_process_information_entries, 1); + assert_eq!(data.catalog.catalog_offset_sub_chunks, 160); + assert_eq!(data.catalog.number_sub_chunks, 7); + assert_eq!(data.catalog.unknown, [0, 0, 0, 0, 0, 0]); + assert_eq!(data.catalog.earliest_firehose_timestamp, 820223379547412); + assert_eq!( + data.catalog.catalog_uuids, + [ + "2BEFD20C18EC3838814F2B4E5AF3BCEC", + "3D05845F3F65358F9EBF2236E772AC01" + ] + ); + assert_eq!( + data.catalog.catalog_subsystem_strings, + [ + 99, 111, 109, 46, 97, 112, 112, 108, 101, 46, 83, 107, 121, 76, 105, 103, 104, 116, + 0, 112, 101, 114, 102, 111, 114, 109, 97, 110, 99, 101, 95, 105, 110, 115, 116, + 114, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 0, 116, 114, 97, 99, 105, + 110, 103, 46, 115, 116, 97, 108, 108, 115, 0, 0, 0 + ] + ); + assert_eq!(data.catalog.catalog_process_info_entries.len(), 1); + assert_eq!( + data.catalog.catalog_process_info_entries[0].main_uuid, + "2BEFD20C18EC3838814F2B4E5AF3BCEC" + ); + assert_eq!( + data.catalog.catalog_process_info_entries[0].dsc_uuid, + "3D05845F3F65358F9EBF2236E772AC01" + ); + + assert_eq!(data.catalog.catalog_subchunks.len(), 7) + } + + #[test] + fn test_get_chunkset_data() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Chunkset Tests/high_sierra_compressed_chunkset.raw"); + + let buffer = fs::read(test_path).unwrap(); + + let mut unified_log = UnifiedLogCatalogData { + catalog: CatalogChunk { + chunk_tag: 0, + chunk_sub_tag: 0, + chunk_data_size: 0, + catalog_subsystem_strings_offset: 0, + catalog_process_info_entries_offset: 0, + number_process_information_entries: 0, + catalog_offset_sub_chunks: 0, + number_sub_chunks: 0, + unknown: Vec::new(), + earliest_firehose_timestamp: 0, + catalog_uuids: Vec::new(), + catalog_subsystem_strings: Vec::new(), + catalog_process_info_entries: Vec::new(), + catalog_subchunks: Vec::new(), + }, + firehose: Vec::new(), + simpledump: Vec::new(), + statedump: Vec::new(), + oversize: Vec::new(), + }; + + let mut log_data = UnifiedLogData { + header: Vec::new(), + catalog_data: Vec::new(), + oversize: Vec::new(), + }; + + LogData::get_chunkset_data(&buffer, &mut unified_log, &mut log_data); + assert_eq!(unified_log.catalog.chunk_tag, 0); + assert_eq!(unified_log.firehose.len(), 21); + assert_eq!(unified_log.statedump.len(), 0); + assert_eq!(unified_log.simpledump.len(), 0); + assert_eq!(unified_log.oversize.len(), 0); + + assert_eq!( + unified_log.firehose[0].public_data[0].message.item_info[0].message_strings, + "483.700" + ); + assert_eq!(unified_log.firehose[0].base_continous_time, 0); + assert_eq!(unified_log.firehose[0].first_number_proc_id, 70); + assert_eq!(unified_log.firehose[0].second_number_proc_id, 71); + assert_eq!(unified_log.firehose[0].public_data_size, 4040); + assert_eq!(unified_log.firehose[0].private_data_virtual_offset, 4096); + } + + #[test] + fn test_track_missing() { + let first_proc_id = 1; + let second_proc_id = 2; + let time = 11; + let test_firehose = Firehose { + unknown_log_activity_type: 0, + unknown_log_type: 0, + flags: 0, + format_string_location: 0, + thread_id: 0, + continous_time_delta: 0, + continous_time_delta_upper: 0, + data_size: 0, + firehose_activity: FirehoseActivity { + unknown_activity_id: 0, + unknown_sentinal: 0, + pid: 0, + unknown_activity_id_2: 0, + unknown_sentinal_2: 0, + unknown_activity_id_3: 0, + unknown_sentinal_3: 0, + unknown_message_string_ref: 0, + unknown_pc_id: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + }, + firehose_non_activity: FirehoseNonActivity { + unknown_activity_id: 0, + unknown_sentinal: 0, + private_strings_offset: 0, + private_strings_size: 0, + unknown_message_string_ref: 0, + subsystem_value: 0, + ttl_value: 0, + data_ref_value: 0, + unknown_pc_id: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + }, + firehose_loss: FirehoseLoss { + start_time: 0, + end_time: 0, + count: 0, + }, + firehose_trace: FirehoseTrace { + unknown_pc_id: 0, + message_value: 0, + unknown_data: Vec::new(), + }, + firehose_signpost: FirehoseSignpost { + unknown_pc_id: 0, + unknown_activity_id: 0, + unknown_sentinel: 0, + subsystem: 0, + signpost_id: 0, + signpost_name: 0, + private_strings_offset: 0, + private_strings_size: 0, + ttl_value: 0, + firehose_formatters: FirehoseFormatters { + main_exe: false, + shared_cache: false, + has_large_offset: 0, + large_shared_cache: 0, + absolute: false, + uuid_relative: String::new(), + main_plugin: false, + pc_style: false, + main_exe_alt_index: 0, + }, + data_ref_value: 0, + }, + unknown_item: 0, + number_items: 0, + message: FirehoseItemData { + item_info: Vec::new(), + backtrace_strings: Vec::new(), + }, + }; + + let missing_firehose = + LogData::track_missing(first_proc_id, second_proc_id, time, test_firehose); + assert_eq!(missing_firehose.first_number_proc_id, first_proc_id); + assert_eq!(missing_firehose.second_number_proc_id, second_proc_id); + assert_eq!(missing_firehose.base_continous_time, time); + } + + #[test] + fn test_add_missing() { + let mut missing_unified_log_data_vec = UnifiedLogData { + header: Vec::new(), + catalog_data: Vec::new(), + oversize: Vec::new(), + }; + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push( + "tests/test_data/system_logs_big_sur.logarchive/Persist/0000000000000002.tracev3", + ); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + LogData::add_missing( + &log_data.catalog_data[0], + 0, + 0, + &log_data.header, + &mut missing_unified_log_data_vec, + &log_data.catalog_data[0].firehose[0], + ); + assert_eq!(missing_unified_log_data_vec.header.len(), 1); + assert_eq!( + missing_unified_log_data_vec.header[0].boot_uuid, + "80D194AF56A34C54867449D2130D41BB" + ); + assert_eq!(missing_unified_log_data_vec.header[0].logd_pid, 42); + assert_eq!(missing_unified_log_data_vec.catalog_data.len(), 1); + assert_eq!( + missing_unified_log_data_vec.catalog_data[0] + .catalog + .catalog_subsystem_strings_offset, + 848 + ); + assert_eq!( + missing_unified_log_data_vec.catalog_data[0].firehose.len(), + 1 + ); + assert_eq!( + missing_unified_log_data_vec.catalog_data[0].firehose[0].first_number_proc_id, + 45 + ); + assert_eq!( + missing_unified_log_data_vec.catalog_data[0].firehose[0].second_number_proc_id, + 188 + ); + } +} diff --git a/src/util.rs b/src/util.rs new file mode 100755 index 0000000..652f497 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,148 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::{error, warn}; +use std::str::from_utf8; + +use nom::bytes::complete::take; +use nom::bytes::complete::take_while; + +/// Calculate 8 byte padding +pub fn padding_size(data: u64) -> u64 { + let alignment = 8; + // Calculate padding to achieve 64-bit alignment + (alignment - (data & (alignment - 1))) & (alignment - 1) +} + +/// Calculate 4 byte padding +pub fn padding_size_four(data: u64) -> u64 { + let alignment = 4; + // Calculate padding to achieve 64-bit alignment + (alignment - (data & (alignment - 1))) & (alignment - 1) +} + +/// Extract a size based on provided string size from Firehose string item entries +pub fn extract_string_size(data: &[u8], message_size: u64) -> nom::IResult<&[u8], String> { + let null_string = 0; + if message_size == null_string { + return Ok((data, String::from("(null)"))); + } + + // If our remaining data is smaller than the message string size just go until the end of the remaining data + if data.len() < message_size as usize { + // Get whole string message except end of string (0s) + let (input, path) = take(data.len())(data)?; + let path_string = String::from_utf8(path.to_vec()); + match path_string { + Ok(results) => return Ok((input, results.trim_end_matches(char::from(0)).to_string())), + Err(err) => error!( + "[macos-unifiedlogs] Failed to get extract specific string size: {:?}", + err + ), + } + } + + // Get whole string message except end of string (0s) + let (input, path) = take(message_size)(data)?; + + let path_string = String::from_utf8(path.to_vec()); + + match path_string { + Ok(results) => return Ok((input, results.trim_end_matches(char::from(0)).to_string())), + Err(err) => error!( + "[macos-unifiedlogs] Failed to get specific string: {:?}", + err + ), + } + Ok((input, String::from("Could not find path string"))) +} + +/// Extract strings that contain end of string characters +pub fn extract_string(data: &[u8]) -> nom::IResult<&[u8], String> { + let last_value = data.last(); + match last_value { + Some(value) => { + let has_end_of_string: u8 = 0; + + // If message data does not end with end of string character (0) + // just grab everything and convert what we have to string + if value != &has_end_of_string { + let (input, path) = take(data.len())(data)?; + let path_string = from_utf8(path); + match path_string { + Ok(results) => return Ok((input, results.to_string())), + Err(err) => { + warn!( + "[macos-unifiedlogs] Failed to get no end of character string: {:?}", + err + ); + return Ok((input, String::from("Could not extract string"))); + } + } + } + } + None => { + error!("[macos-unifiedlogs] Can not extract string. Empty input."); + return Ok((data, String::from("Can not extract string. Empty input."))); + } + } + + let (input, path) = take_while(|b: u8| b != 0)(data)?; + let path_string = from_utf8(path); + match path_string { + Ok(results) => { + return Ok((input, results.to_string())); + } + Err(err) => { + warn!("[macos-unifiedlogs] Failed to get string: {:?}", err); + } + } + Ok((input, String::from("Could not extract string"))) +} + +/// Clean and format UUIDs to be pretty +pub fn clean_uuid(uuid_format: &str) -> String { + uuid_format + .replace(',', "") + .replace('[', "") + .replace(']', "") + .replace(' ', "") +} + +#[cfg(test)] +mod tests { + use crate::util::{extract_string, extract_string_size, padding_size, padding_size_four}; + + #[test] + fn test_padding_size() { + let data = 8; + let results = padding_size(data); + assert_eq!(results, 0); + } + + #[test] + fn test_padding_size_four() { + let data = 4; + let results = padding_size_four(data); + assert_eq!(results, 0); + } + + #[test] + fn test_extract_string_size() { + let test_data = [55, 57, 54, 46, 49, 48, 48, 0]; + let test_size = 8; + let (_, results) = extract_string_size(&test_data, test_size).unwrap(); + assert_eq!(results, "796.100"); + } + + #[test] + fn test_extract_string() { + let test_data = [55, 57, 54, 46, 49, 48, 48, 0]; + let (_, results) = extract_string(&test_data).unwrap(); + assert_eq!(results, "796.100"); + } +} diff --git a/src/uuidtext.rs b/src/uuidtext.rs new file mode 100755 index 0000000..acca1f5 --- /dev/null +++ b/src/uuidtext.rs @@ -0,0 +1,164 @@ +// Copyright 2022 Mandiant, Inc. All Rights Reserved +// 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. + +use log::error; +use nom::bytes::complete::take; +use nom::number::complete::le_u32; +use nom::Needed; +use std::mem::size_of; + +#[derive(Debug)] +pub struct UUIDText { + pub uuid: String, + pub signature: u32, + pub unknown_major_version: u32, + pub unknown_minor_version: u32, + pub number_entries: u32, + pub entry_descriptors: Vec, + pub footer_data: Vec, // Collection of strings containing sender process/library with end of string characters +} +#[derive(Debug)] +pub struct UUIDTextEntry { + pub range_start_offset: u32, + pub entry_size: u32, +} +impl UUIDText { + /// Parse the UUID files in uuidinfo directory. Contains the base log message string + pub fn parse_uuidtext(data: &[u8]) -> nom::IResult<&[u8], UUIDText> { + let mut uuidtext_data = UUIDText { + uuid: String::new(), + signature: 0, + unknown_major_version: 0, + unknown_minor_version: 0, + number_entries: 0, + entry_descriptors: Vec::new(), + footer_data: Vec::new(), + }; + + let expected_uuidtext_signature = 0x66778899; + let (input, signature) = take(size_of::())(data)?; + let (_, uuidtext_signature) = le_u32(signature)?; + + if expected_uuidtext_signature != uuidtext_signature { + error!( + "[macos-unifiedlogs] Incorrect UUIDText header signature. Expected {}. Got: {}", + expected_uuidtext_signature, uuidtext_signature + ); + return Err(nom::Err::Incomplete(Needed::Unknown)); + } + + let (input, unknown_major_version) = take(size_of::())(input)?; + let (input, unknown_minor_version) = take(size_of::())(input)?; + let (mut input, number_entries) = take(size_of::())(input)?; + + let (_, uuidtext_unknown_major_version) = le_u32(unknown_major_version)?; + let (_, uuidtext_unknown_minor_version) = le_u32(unknown_minor_version)?; + let (_, uuidtext_number_entries) = le_u32(number_entries)?; + + uuidtext_data.signature = uuidtext_signature; + uuidtext_data.unknown_major_version = uuidtext_unknown_major_version; + uuidtext_data.unknown_minor_version = uuidtext_unknown_minor_version; + uuidtext_data.number_entries = uuidtext_number_entries; + + let mut count = 0; + while count < uuidtext_number_entries { + let (entry_input, range_start_offset) = take(size_of::())(input)?; + let (entry_input, entry_size) = take(size_of::())(entry_input)?; + + let (_, uuidtext_range_start_offset) = le_u32(range_start_offset)?; + let (_, uuidtext_entry_size) = le_u32(entry_size)?; + + let entry_data = UUIDTextEntry { + range_start_offset: uuidtext_range_start_offset, + entry_size: uuidtext_entry_size, + }; + uuidtext_data.entry_descriptors.push(entry_data); + + input = entry_input; + count += 1; + } + uuidtext_data.footer_data = input.to_vec(); + Ok((input, uuidtext_data)) + } +} + +#[cfg(test)] +mod tests { + use crate::uuidtext::UUIDText; + use std::fs; + use std::path::PathBuf; + + #[test] + fn test_parse_uuidtext_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/UUIDText/Big Sur/1FE459BBDC3E19BBF82D58415A2AE9"); + + let buffer = fs::read(test_path).unwrap(); + + let (_, uuidtext_data) = UUIDText::parse_uuidtext(&buffer).unwrap(); + assert_eq!(uuidtext_data.signature, 0x66778899); + assert_eq!(uuidtext_data.unknown_major_version, 2); + assert_eq!(uuidtext_data.unknown_minor_version, 1); + assert_eq!(uuidtext_data.number_entries, 2); + assert_eq!(uuidtext_data.entry_descriptors[0].entry_size, 617); + assert_eq!(uuidtext_data.entry_descriptors[1].entry_size, 2301); + + assert_eq!(uuidtext_data.entry_descriptors[0].range_start_offset, 32048); + assert_eq!(uuidtext_data.entry_descriptors[1].range_start_offset, 29747); + assert_eq!(uuidtext_data.footer_data.len(), 2987); + } + + #[test] + fn test_parse_uuidtext_high_sierra() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/UUIDText/High Sierra/425A2E5B5531B98918411B4379EE5F"); + + let buffer = fs::read(test_path).unwrap(); + + let (_, uuidtext_data) = UUIDText::parse_uuidtext(&buffer).unwrap(); + assert_eq!(uuidtext_data.signature, 0x66778899); + assert_eq!(uuidtext_data.unknown_major_version, 2); + assert_eq!(uuidtext_data.unknown_minor_version, 1); + assert_eq!(uuidtext_data.number_entries, 1); + assert_eq!(uuidtext_data.entry_descriptors[0].entry_size, 2740); + assert_eq!(uuidtext_data.entry_descriptors[0].range_start_offset, 21132); + + assert_eq!(uuidtext_data.footer_data.len(), 2951); + } + + #[test] + #[should_panic(expected = "Incomplete(Unknown)")] + fn test_bad_header() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path + .push("tests/test_data/Bad Data/UUIDText/Bad_Header_1FE459BBDC3E19BBF82D58415A2AE9"); + + let buffer = fs::read(test_path).unwrap(); + let (_, _) = UUIDText::parse_uuidtext(&buffer).unwrap(); + } + + #[test] + #[should_panic(expected = "Eof")] + fn test_bad_content() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path + .push("tests/test_data/Bad Data/UUIDText/Bad_Content_1FE459BBDC3E19BBF82D58415A2AE9"); + + let buffer = fs::read(test_path).unwrap(); + let (_, _) = UUIDText::parse_uuidtext(&buffer).unwrap(); + } + + #[test] + #[should_panic(expected = "Incomplete(Unknown)")] + fn test_bad_file() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/Bad Data/UUIDText/Badfile.txt"); + + let buffer = fs::read(test_path).unwrap(); + let (_, _) = UUIDText::parse_uuidtext(&buffer).unwrap(); + } +}